diff --git a/.env.example b/.env.example index 07772de..3b1c3e1 100644 --- a/.env.example +++ b/.env.example @@ -203,3 +203,45 @@ NEXT_PRIVATE_LOGGER_FILE_PATH= # [[PLAIN SUPPORT]] NEXT_PRIVATE_PLAIN_API_KEY= + +# [[DISCOVERY — „Dokumente finden"]] +# Wählt das Discovery-Reader-Backend für die Funktion „Dokumente finden". +# Optionen: +# "db" (Default) – liest aus der DiscoveryDocument-Tabelle (Source-Sync und +# manueller Intake-Upload schreiben dort hinein). +# "paperless" – externer Indexdienst per REST-API. +# "null" – Stub, leere Listen. +NEXT_PRIVATE_DISCOVERY_TRANSPORT="db" + +# Pflicht, wenn TRANSPORT="paperless": +NEXT_PRIVATE_DISCOVERY_PAPERLESS_URL="" +NEXT_PRIVATE_DISCOVERY_PAPERLESS_TOKEN="" + +# [[SOURCES — IMAP-Sync]] +# Eigener Schlüssel zur Verschlüsselung der IMAP-Credentials. Mind. 32 Zeichen. +# Falls leer, wird NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY als Fallback genutzt — +# eigener Schlüssel ist aber dringend empfohlen, damit IMAP-Credentials +# unabhängig vom Rest rotiert werden können. +NEXT_PRIVATE_IMAP_CREDENTIAL_KEY="" + +# Custom-Hosts erlauben? Wenn "true", können Nutzer eigene IMAP-Server eintragen. +# Default-Mainstream-Hosts (Gmail, Outlook, Fastmail, T-Online, GMX, Web.de, +# Mailbox.org, Posteo, iCloud, Yahoo) sind immer erlaubt. Custom-Hosts werden +# per DNS gegen private und reservierte IP-Bereiche geprüft. +NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS="false" + +# Optional: zusätzliche Hostnames zur Allowlist (komma-getrennt). Werden auch +# bei `NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS=false` akzeptiert. +NEXT_PRIVATE_IMAP_HOST_ALLOWLIST="" + +# Filesystem-Pfad für das Discovery-Archiv (Mail.eml + Body + Anhänge + +# metadata.json + sha256). Pro Mail wird ein Ordner +# ///// angelegt. Read-only nach +# dem Schreiben (chmod 0440 / 0550), GoBD-Beweisfähigkeit via sha256-Hashes +# pro Datei. In der Compose-Variante ist /var/lib/nexasign/sources im +# Container, gemounted vom Host-Pfad ARCHIVE_HOST_PATH. +NEXT_PRIVATE_DISCOVERY_ARCHIVE_PATH="/var/lib/nexasign/sources" + +# Host-Pfad für den Volume-Mount (nur in docker-compose nötig). Hier landet +# dein per FTP/SCP erreichbares Archiv. +# ARCHIVE_HOST_PATH="/var/lib/nexasign-archive" diff --git a/.gitignore b/.gitignore index 10c7e97..ab082e5 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,9 @@ Emilian Buza.jpg img/26864.jpg packages/assets/images/emilian.webp +# Logo-Backups (Originale liegen nur lokal als Wiederherstellungs-Punkt) +img/*.original.png + # Generierte Logo-Artefakte (Zwischenstände bei Logo-Generierung) tmp-logo/ @@ -98,6 +101,8 @@ tmp-logo/ # Diese Dateien gehören in ein privates NexaStack-Infra-Repo, nicht hierher. # Falls sie versehentlich lokal landen, blockiert .gitignore das Tracking. archive/ +!packages/lib/server-only/sources/archive/ +!packages/lib/server-only/sources/archive/** demo/ Demo/ DEMO.nexasign.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0a8c571..716d312 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,10 +1,10 @@ -# NexaSign Architecture +# NexaFile Architecture -This document provides a high-level overview of the NexaSign codebase to help humans and agents understand how the application is structured. +This document provides a high-level overview of the NexaFile codebase to help humans and agents understand how the application is structured. ## Overview -NexaSign is an open-source document signing platform built as a **monorepo** using npm workspaces and Turborepo. The application enables users to create, send, and sign documents electronically. +NexaFile is an open-source document lifecycle platform built as a **monorepo** using npm workspaces and Turborepo. The application enables users to find, create, send, sign, and archive documents. ``` ┌─────────────────────────────────────────────────────────────────────────────┐ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a92f02c..73b0792 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,9 @@ -# Contributing to NexaSign +# Contributing to NexaFile -Danke für Ihr Interesse an NexaSign. Beiträge (Bugfixes, Features, Docs, +Danke für Ihr Interesse an NexaFile. Beiträge (Bugfixes, Features, Docs, Übersetzungen) sind willkommen. ## Quick links @@ -36,6 +36,6 @@ Erforderlich: Node.js ≥ 22, Docker, npm 10+. ## Lizenz der Beiträge -Mit Ihrem Beitrag zu NexaSign erklären Sie sich einverstanden, dass Ihr Code +Mit Ihrem Beitrag zu NexaFile erklären Sie sich einverstanden, dass Ihr Code unter **AGPL-3.0-or-later** lizenziert wird — derselben Lizenz wie der Rest des Projekts. Kein separates CLA erforderlich. Siehe [LICENSE](LICENSE). diff --git a/README.md b/README.md index d77fd2c..16f641c 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ -# NexaSign +# NexaFile -**Die deutsche, selbstgehostete Alternative zu DocuSign.** +**Die deutsche, selbstgehostete Dokumentenplattform für Finden, Signieren und Archivieren.** -NexaSign signiert elektronische Dokumente rechtskonform nach eIDAS — komplett -in Ihrer eigenen Infrastruktur. Keine Daten in US-Clouds, kein Abo-Zwang, -keine Drittanbieter-Server im Signatur-Pfad. +NexaFile findet, signiert und archiviert elektronische Dokumente in Ihrer eigenen +Infrastruktur. Keine Daten in US-Clouds, kein Abo-Zwang, keine Drittanbieter-Server +im Signatur- oder Archiv-Pfad. Gepflegt von [NexaStack](https://nexastack.co/) als Open-Source-Projekt unter AGPL-3.0-or-later. --- -## 🔎 NexaSign live ausprobieren, bevor Sie selbst hosten +## 🔎 NexaFile live ausprobieren, bevor Sie selbst hosten **→ [nexasign-demo.nexastack.co](https://nexasign-demo.nexastack.co)** @@ -28,7 +28,14 @@ ersten Eindruck zu bekommen, bevor Sie den eigenen Stack aufsetzen. --- -## Was NexaSign kann +## Was NexaFile kann + +**Dokumente finden und übernehmen:** + +- IMAP-Quellen gezielt für frei wählbare Datumsbereiche synchronisieren +- E-Mails, Anhänge, Body-Dateien und Metadaten lokal archivieren +- Gefundene Belege prüfen, akzeptieren und mit Retention-Start versehen +- Auditierbare Discovery-Logs und Exportfähigkeit für Betriebsprüfungen **E-Signatur, rechtskonform und self-hosted:** @@ -61,7 +68,7 @@ ersten Eindruck zu bekommen, bevor Sie den eigenen Stack aufsetzen. ## Hinweis zur Schriftform -NexaSign erzeugt **einfache und fortgeschrittene elektronische Signaturen (EES/AES)**. +NexaFile erzeugt **einfache und fortgeschrittene elektronische Signaturen (EES/AES)**. Das reicht für die allermeisten Verträge im deutschen Geschäftsalltag (AGB-Zustimmungen, NDAs, Freelance-Verträge, Dienstleistungen, Angebote), da diese nach § 125 BGB formfrei sind. @@ -70,13 +77,13 @@ Für Verträge mit gesetzlicher **Schriftform-Pflicht** (z. B. Mietverträge > 1 Jahr, bestimmte Kündigungen, Arbeitszeugnisse) wird eine **qualifizierte elektronische Signatur (QES)** nach eIDAS Art. 25 benötigt. Diese erfordert einen akkreditierten Vertrauensdiensteanbieter (z. B. D-Trust / Bundesdruckerei) -und ist in NexaSign aktuell **nicht** integriert. +und ist in NexaFile aktuell **nicht** integriert. --- ## Hinweis zu GoBD und Aufbewahrung -NexaSign liefert **GoBD-Tooling** (WORM-Strict-Mode, 10-Jahres-Retention nach +NexaFile liefert **GoBD-Tooling** (WORM-Strict-Mode, 10-Jahres-Retention nach § 147 AO / § 257 HGB, Z2/Z3-Export-CLI mit SHA-256-Manifest). Das ist die technische Basis für eine GoBD-orientierte Aufbewahrung — **nicht** der fertige GoBD-Nachweis. @@ -92,7 +99,7 @@ abgestimmt. Eine Vorlage für die Verfahrensdokumentation liegt unter ## Installation (Self-Hosting) -NexaSign besteht aus zwei Teilen: +NexaFile besteht aus zwei Teilen: 1. **E-Signatur-App** — Docker, Port 3060 (Pflicht) 2. **Vorlagen-Tools** (`/vorlagen/*`, AV-Vertrag, X-Rechnung, GoBD) — PHP auf Host, **optional** @@ -199,11 +206,12 @@ Details in [CONTRIBUTING.md](CONTRIBUTING.md). - **Haftung:** Die Software wird **ohne jede Gewährleistung** bereitgestellt (§§ 15/16 AGPL-3.0). Bei unentgeltlicher Überlassung gilt zusätzlich § 521 BGB analog — Haftung nur bei Vorsatz und grober Fahrlässigkeit. -- **Keine Rechtsberatung:** Die Ausgabe einer Signatur durch NexaSign ersetzt +- **Keine Rechtsberatung:** Die Ausgabe einer Signatur durch NexaFile ersetzt **keine juristische Prüfung** der unterzeichneten Dokumente. - **Betrieb als Service:** AGPL-3.0 verlangt, dass alle Nutzer des Services - Zugang zum Quellcode haben. Der gesamte NexaSign-Source liegt öffentlich - in diesem Repo. + Zugang zum Quellcode haben. Der gesamte NexaFile-Source liegt öffentlich + in diesem Repo. Technische Paket-, Docker- und Datenbanknamen verwenden in V1 + aus Kompatibilitätsgründen teilweise weiterhin `nexasign`. ## Sicherheit diff --git a/RELEASE-V1.md b/RELEASE-V1.md new file mode 100644 index 0000000..5d0b9dc --- /dev/null +++ b/RELEASE-V1.md @@ -0,0 +1,71 @@ +# NexaFile V1 Release Plan + +This file defines the practical V1 scope for NexaFile. Package names, +Docker service names, database names, and CLI filenames may stay `nexasign` +for V1 to avoid risky infrastructure churn. User-facing product copy should +move to `NexaFile`. + +## V1 Product Scope + +NexaFile V1 is a self-hosted document lifecycle for German small and midsize +businesses: + +1. Create documents: contract templates, AV-Vertrag, X-Rechnung/ZUGFeRD tools. +2. Find documents: IMAP sources, explicit date-range sync, invoice/document + detection, server-side mail and attachment archive. +3. Sign documents: the existing signing workflow, recipients, fields, audit log, + signed PDF sealing. +4. Archive documents: GoBD-oriented retention start, WORM guards, SHA-256 based + export package, retention reporting. + +## Explicitly Not V1 + +- Qualified electronic signatures (QES). +- Background auto-sync every few minutes. +- Cloud sources beyond IMAP. +- Full-text document search across all archived bytes. +- Formal GoBD certification or legal/tax advice. +- Renaming all internal package names, DB containers, service names, and CLI + filenames from `nexasign` to `nexafile`. + +## Release-Critical Checks + +- Fresh install from `docker/nexasign/compose.yml` on a clean host. +- Prisma migrations deploy cleanly, including Discovery retention backfill. +- Signing happy path completes and produces sealed PDFs. +- IMAP source can be created with allowed host, explicit SyncRun can import a + PDF invoice, and duplicate SyncRuns do not duplicate `DiscoveryDocument`s. +- `Dokumente finden` can accept, archive, ignore, create a signing document, + download artifacts, and export selected documents as ZIP. +- GoBD export includes completed Envelopes, accepted DiscoveryDocuments, + Discovery audit logs, mail artifacts, document PDFs, and `manifest.sha256`. +- Retention check reports both completed Envelopes and accepted + DiscoveryDocuments without deleting anything. +- Security checks cover IMAP host validation, path traversal prevention for + artifacts and ZIP export, ZIP size limits, team/user isolation, and HTML mail + display restrictions. + +## Rebranding Policy + +Use `NexaFile` in visible product UI, README/installation copy, metadata, +OpenGraph titles, email copy, and docs. Keep `NexaSign` where it is part of +compatibility-sensitive identifiers for V1: + +- npm package names such as `@nexasign/*` +- Docker compose project/container/volume names +- database names and migration history +- existing CLI filenames and systemd unit filenames +- legacy attribution to the NexaSign fork history + +## V1 Release Sequence + +1. Finish and review current Discovery/GoBD local changes. +2. Apply and test the Discovery retention backfill migration. +3. Complete user-facing NexaFile copy pass. +4. Add focused Discovery/GoBD checks to the release gate. +5. Run the release gate and fresh-install smoke test. +6. Deploy demo, manually verify the four-step navigation and core workflows. +7. Tag `v1.0.0-rc.1`. +8. Fix release-candidate findings. +9. Tag `v1.0.0`. + diff --git a/Rechnungen erstellen/rechnungen.py b/Rechnungen erstellen/rechnungen.py new file mode 100644 index 0000000..db44a34 --- /dev/null +++ b/Rechnungen erstellen/rechnungen.py @@ -0,0 +1,690 @@ +#!/usr/bin/env python3 +""" +rechnungen.py – Lädt Rechnungs-PDFs aus einem Gmail-Postfach für einen Zeitraum. + +Verwendung: + python3 rechnungen.py --email du@gmail.com --year 2026 --month 04 + python3 rechnungen.py --email du@gmail.com --from 2026-01-01 --to 2026-12-31 + python3 rechnungen.py --email du@gmail.com --year 2025 --month 12 --output ./archiv + python3 rechnungen.py --email du@gmail.com --year 2026 --month 04 --verbose + python3 rechnungen.py --email du@gmail.com --year 2026 --month 04 --quiet + +Voraussetzung: + Gmail App-Passwort (Google-Konto -> Sicherheit -> 2FA -> App-Passwörter). + Wird interaktiv abgefragt, nicht gespeichert. + +Optional Konfiguration: + ~/.rechnungen.json kann zusätzliche Domains/Keywords enthalten: + { + "known_domains": ["weiterer-anbieter.de"], + "keywords": ["mahngebühr"], + "ignore_keywords": ["spendenaufruf"], + "portal_hints": ["bitte einloggen unter"] + } + +Output: + ./rechnungen/-/ + / + __.pdf + _gezogen.csv – alle automatisch gezogenen Rechnungen + _manuell_ziehen.csv – Rechnungs-Mails ohne PDF (Portal-Logins etc.) + _log.txt – Verarbeitungsprotokoll + _seen.json – Cache verarbeiteter Message-IDs (Idempotenz) +""" + +from __future__ import annotations + +import argparse +import csv +import email +import email.header +import email.utils +import getpass +import imaplib +import io +import json +import logging +import re +import sys +import time +import zipfile +from collections.abc import Iterable +from dataclasses import dataclass, field +from datetime import date, datetime +from email.message import Message +from pathlib import Path + +# ---------------------------------------------------------------------------- +# Konfiguration – hier erweiterbar ohne Code-Logik anzufassen +# ---------------------------------------------------------------------------- + +IMAP_HOST = "imap.gmail.com" +IMAP_PORT = 993 +MAILBOX = "[Gmail]/Alle Nachrichten" +MAILBOX_FALLBACK = "INBOX" +CONFIG_PATH = Path.home() / ".rechnungen.json" +FETCH_RETRIES = 3 + +# Stichwörter, die auf eine Rechnungs-Mail hindeuten (Betreff oder Body). +RECHNUNG_KEYWORDS: list[str] = [ + "rechnung", "invoice", "beleg", "receipt", "quittung", + "zahlungsbestätigung", "zahlungsbestaetigung", "payment confirmation", + "abrechnung", "gutschrift", "kreditnote", "credit note", + "auftragsbestätigung", "auftragsbestaetigung", "order confirmation", +] + +# Absender-Domains, die wir als verlässliche Rechnungs-Quellen kennen. +KNOWN_RECHNUNG_DOMAINS: set[str] = { + "hetzner.com", "hetzner.de", "netcup.de", "netcup.eu", + "all-inkl.com", "all-inkl.de", "strato.de", "strato.com", + "anthropic.com", "openai.com", "cloudflare.com", + "godaddy.com", "deutschepost.de", "uber.com", "flixbus.de", + "amazon.de", "amazon.com", "paypal.com", "paypal.de", + "telekom.de", "vodafone.de", "o2.de", "1und1.de", "ionos.de", + "premiumsim.de", "congstar.de", + "stripe.com", "suno.com", "github.com", "gitlab.com", + "google.com", "microsoft.com", "apple.com", + "wise.com", "n26.com", "dkb.de", "comdirect.de", "ing.de", +} + +# Stichwörter, die eine Mail als Werbung/Newsletter disqualifizieren. +IGNORE_KEYWORDS: list[str] = [ + "newsletter", "unsubscribe", "abmelden", + "sale", "rabatt", "% off", +] + +# Portal-Hinweise: Mail enthält Rechnungs-Indikator, aber kein PDF. +PORTAL_HINTS: list[str] = [ + "im kundenportal", "im kundencenter", "in der servicewelt", + "in ihrem konto", "im kundenlogin", "in ihrem account", + "log in to", "anmelden unter", "rechnung abrufen", + "rechnung steht zum download bereit", "view your invoice", + "im ccp", "control panel", +] + + +def load_user_config() -> None: + """Erweitert globale Listen aus ~/.rechnungen.json (falls vorhanden).""" + if not CONFIG_PATH.exists(): + return + try: + cfg = json.loads(CONFIG_PATH.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError) as e: + logging.getLogger("rechnungen").warning( + "Konnte %s nicht lesen: %s", CONFIG_PATH, e + ) + return + KNOWN_RECHNUNG_DOMAINS.update(d.lower() for d in cfg.get("known_domains", [])) + RECHNUNG_KEYWORDS.extend(k.lower() for k in cfg.get("keywords", [])) + IGNORE_KEYWORDS.extend(k.lower() for k in cfg.get("ignore_keywords", [])) + PORTAL_HINTS.extend(p.lower() for p in cfg.get("portal_hints", [])) + + +# ---------------------------------------------------------------------------- +# Datentypen +# ---------------------------------------------------------------------------- + +@dataclass +class MailRef: + """Eine Mail im Verarbeitungskontext.""" + uid: str + message_id: str + sender_name: str + sender_email: str + sender_domain: str + subject: str + date: datetime + body_text: str + # tuple: (filename, content, from_zip) + pdf_attachments: list[tuple[str, bytes, bool]] = field(default_factory=list) + + +@dataclass(frozen=True) +class GezogeneRechnung: + sender_domain: str + sender_email: str + date: str + subject: str + amount: str + invoice_number: str + file_path: str + from_zip: bool + + +@dataclass(frozen=True) +class ManuelleAufgabe: + sender_domain: str + sender_email: str + date: str + subject: str + amount_hint: str + portal_hint: str + grund: str + + +# ---------------------------------------------------------------------------- +# Logging +# ---------------------------------------------------------------------------- + +def setup_logging(out_root: Path, verbose: bool, quiet: bool) -> logging.Logger: + out_root.mkdir(parents=True, exist_ok=True) + level = logging.DEBUG if verbose else (logging.WARNING if quiet else logging.INFO) + + log = logging.getLogger("rechnungen") + log.setLevel(logging.DEBUG) + log.handlers.clear() # Doppel-Handler bei wiederholtem Aufruf vermeiden + + fmt = logging.Formatter( + "%(asctime)s %(levelname)s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + console = logging.StreamHandler(sys.stdout) + console.setFormatter(fmt) + console.setLevel(level) + log.addHandler(console) + + file_handler = logging.FileHandler(out_root / "_log.txt", encoding="utf-8") + file_handler.setFormatter(fmt) + file_handler.setLevel(logging.DEBUG) # Datei kriegt immer alles + log.addHandler(file_handler) + + return log + + +# ---------------------------------------------------------------------------- +# CLI +# ---------------------------------------------------------------------------- + +def parse_args() -> argparse.Namespace: + p = argparse.ArgumentParser( + description="Lädt Rechnungs-PDFs aus einem Gmail-Postfach.", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=__doc__, + ) + p.add_argument("--email", required=True, help="Gmail-Adresse") + p.add_argument("--year", type=int, help="Jahr, z.B. 2026") + p.add_argument("--month", type=int, help="Monat 1-12") + p.add_argument("--from", dest="date_from", help="Startdatum YYYY-MM-DD") + p.add_argument("--to", dest="date_to", help="Enddatum YYYY-MM-DD (exklusiv)") + p.add_argument("--output", default="./rechnungen", + help="Ausgabe-Basisverzeichnis (Default: ./rechnungen)") + p.add_argument("--mailbox", default=MAILBOX, + help=f"IMAP-Mailbox (Default: {MAILBOX})") + verbosity = p.add_mutually_exclusive_group() + verbosity.add_argument("--verbose", "-v", action="store_true", + help="Mehr Log-Output (DEBUG-Level)") + verbosity.add_argument("--quiet", "-q", action="store_true", + help="Nur Warnungen/Fehler auf der Konsole") + args = p.parse_args() + + if args.date_from or args.date_to: + if not (args.date_from and args.date_to): + p.error("--from und --to müssen zusammen verwendet werden.") + try: + args._from = datetime.strptime(args.date_from, "%Y-%m-%d").date() + args._to = datetime.strptime(args.date_to, "%Y-%m-%d").date() + except ValueError as e: + p.error(f"Ungültiges Datum: {e}") + args._label = f"{args.date_from}_bis_{args.date_to}" + elif args.year and args.month: + if not (1 <= args.month <= 12): + p.error("--month muss 1-12 sein.") + args._from = date(args.year, args.month, 1) + if args.month == 12: + args._to = date(args.year + 1, 1, 1) + else: + args._to = date(args.year, args.month + 1, 1) + args._label = f"{args.year}-{args.month:02d}" + else: + p.error("Entweder --year und --month, oder --from und --to angeben.") + + return args + + +# ---------------------------------------------------------------------------- +# IMAP +# ---------------------------------------------------------------------------- + +def connect(email_addr: str, app_password: str, mailbox: str) -> imaplib.IMAP4_SSL: + conn = imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT) + conn.login(email_addr, app_password) + typ, _ = conn.select(f'"{mailbox}"', readonly=True) + if typ != "OK": + typ, _ = conn.select(MAILBOX_FALLBACK, readonly=True) + if typ != "OK": + raise RuntimeError( + f"Mailbox nicht öffnenbar: {mailbox} und {MAILBOX_FALLBACK}" + ) + return conn + + +def search_uids(conn: imaplib.IMAP4_SSL, date_from: date, date_to: date) -> list[bytes]: + since = date_from.strftime("%d-%b-%Y") + before = date_to.strftime("%d-%b-%Y") + typ, data = conn.uid("SEARCH", None, f"(SINCE {since} BEFORE {before})") + if typ != "OK": + raise RuntimeError(f"IMAP SEARCH fehlgeschlagen: {data!r}") + return data[0].split() if data and data[0] else [] + + +def fetch_mail(conn: imaplib.IMAP4_SSL, uid: bytes) -> Message | None: + typ, data = conn.uid("FETCH", uid, "(RFC822)") + if typ != "OK" or not data or not data[0]: + return None + raw = data[0][1] + if not isinstance(raw, (bytes, bytearray)): + return None + return email.message_from_bytes(raw) + + +def fetch_mail_with_retry( + conn: imaplib.IMAP4_SSL, uid: bytes, log: logging.Logger +) -> Message | None: + """Fetch mit exponential backoff – Gmail-IMAP timed gelegentlich.""" + last_err: Exception | None = None + for attempt in range(FETCH_RETRIES): + try: + return fetch_mail(conn, uid) + except (imaplib.IMAP4.error, ConnectionError, OSError) as e: + last_err = e + if attempt < FETCH_RETRIES - 1: + wait = 2 ** attempt + log.warning("Fetch UID %s fehlgeschlagen (%s), retry in %ds", + uid.decode("ascii", "replace"), e, wait) + time.sleep(wait) + log.error("Fetch UID %s endgültig fehlgeschlagen: %s", + uid.decode("ascii", "replace"), last_err) + return None + + +# ---------------------------------------------------------------------------- +# Mail-Parsing +# ---------------------------------------------------------------------------- + +def decode_header(value: str | None) -> str: + if not value: + return "" + parts = email.header.decode_header(value) + out: list[str] = [] + for text, enc in parts: + if isinstance(text, bytes): + try: + out.append(text.decode(enc or "utf-8", errors="replace")) + except LookupError: + out.append(text.decode("utf-8", errors="replace")) + else: + out.append(text) + return "".join(out).strip() + + +def parse_sender(raw_from: str) -> tuple[str, str, str]: + """Liefert (Anzeigename, Email, Domain).""" + decoded = decode_header(raw_from) + name, addr = email.utils.parseaddr(decoded) + domain = addr.split("@")[-1].lower() if "@" in addr else "" + return name, addr.lower(), domain + + +def parse_date(msg: Message) -> datetime: + raw = msg.get("Date", "") + try: + return email.utils.parsedate_to_datetime(raw) + except (TypeError, ValueError): + return datetime.now() + + +def _decode_part_text(part: Message) -> str | None: + payload = part.get_payload(decode=True) + if not isinstance(payload, (bytes, bytearray)): + return None + charset = part.get_content_charset() or "utf-8" + try: + return payload.decode(charset, errors="replace") + except LookupError: + return payload.decode("utf-8", errors="replace") + + +def extract_body_text(msg: Message) -> str: + """text/plain bevorzugt; HTML-Fallback mit Tag-Strip wenn kein Plaintext da.""" + plain_parts: list[str] = [] + html_parts: list[str] = [] + + iterator: Iterable[Message] = msg.walk() if msg.is_multipart() else [msg] + for part in iterator: + ctype = part.get_content_type() + disp = str(part.get("Content-Disposition", "")) + if "attachment" in disp: + continue + if ctype not in ("text/plain", "text/html"): + continue + text = _decode_part_text(part) + if text is None: + continue + if ctype == "text/plain": + plain_parts.append(text) + else: + stripped = re.sub(r"<[^>]+>", " ", text) + stripped = re.sub(r"\s+", " ", stripped) + html_parts.append(stripped) + + return "\n".join(plain_parts) if plain_parts else "\n".join(html_parts) + + +def _is_pdf_part(part: Message, filename: str | None) -> bool: + if part.get_content_type() == "application/pdf": + return True + return bool(filename and filename.lower().endswith(".pdf")) + + +def _is_zip_part(part: Message, filename: str | None) -> bool: + ctype = part.get_content_type() + if ctype in ("application/zip", "application/x-zip-compressed"): + return True + return bool(filename and filename.lower().endswith(".zip")) + + +def _extract_pdfs_from_zip(blob: bytes, log: logging.Logger) -> list[tuple[str, bytes]]: + out: list[tuple[str, bytes]] = [] + try: + with zipfile.ZipFile(io.BytesIO(blob)) as zf: + for info in zf.infolist(): + if info.is_dir(): + continue + if not info.filename.lower().endswith(".pdf"): + continue + try: + out.append((Path(info.filename).name, zf.read(info))) + except (zipfile.BadZipFile, RuntimeError) as e: + log.warning("Konnte PDF in ZIP nicht lesen (%s): %s", + info.filename, e) + except zipfile.BadZipFile as e: + log.warning("Defektes ZIP-Archiv übersprungen: %s", e) + return out + + +def extract_pdfs(msg: Message, log: logging.Logger) -> list[tuple[str, bytes, bool]]: + """Liefert Liste von (filename, bytes, from_zip).""" + pdfs: list[tuple[str, bytes, bool]] = [] + if not msg.is_multipart(): + return pdfs + for part in msg.walk(): + filename = part.get_filename() + if filename: + filename = decode_header(filename) + payload = part.get_payload(decode=True) + if not isinstance(payload, (bytes, bytearray)): + continue + + if _is_pdf_part(part, filename): + pdfs.append((filename or "rechnung.pdf", bytes(payload), False)) + elif _is_zip_part(part, filename): + for inner_name, inner_blob in _extract_pdfs_from_zip(bytes(payload), log): + pdfs.append((inner_name, inner_blob, True)) + return pdfs + + +def build_mail_ref(uid: bytes, msg: Message, log: logging.Logger) -> MailRef: + name, addr, domain = parse_sender(msg.get("From", "")) + return MailRef( + uid=uid.decode("ascii"), + message_id=(msg.get("Message-ID") or "").strip(), + sender_name=name, + sender_email=addr, + sender_domain=domain, + subject=decode_header(msg.get("Subject", "")), + date=parse_date(msg), + body_text=extract_body_text(msg), + pdf_attachments=extract_pdfs(msg, log), + ) + + +# ---------------------------------------------------------------------------- +# Klassifikation +# ---------------------------------------------------------------------------- + +def has_keyword(text: str, keywords: Iterable[str]) -> bool: + low = text.lower() + return any(k in low for k in keywords) + + +def classify(mail: MailRef) -> str: + """AUTO | MANUAL | IGNORE""" + haystack = f"{mail.subject}\n{mail.body_text}" + + is_known_sender = any( + mail.sender_domain == d or mail.sender_domain.endswith("." + d) + for d in KNOWN_RECHNUNG_DOMAINS + ) + has_rechnung_kw = has_keyword(haystack, RECHNUNG_KEYWORDS) + has_ignore_kw = has_keyword(haystack, IGNORE_KEYWORDS) + + # Bekannter Absender ODER Rechnungs-Keyword reicht. + is_rechnungsmail = is_known_sender or has_rechnung_kw + + if not is_rechnungsmail: + return "IGNORE" + if has_ignore_kw and not is_known_sender: + return "IGNORE" + if mail.pdf_attachments: + return "AUTO" + return "MANUAL" + + +# ---------------------------------------------------------------------------- +# Body-Parsing für Beträge & Rechnungs-Nr. +# ---------------------------------------------------------------------------- + +# Erkennt sowohl "12,99 €" / "12.99 EUR" als auch "$12.99" / "USD 12.99" +AMOUNT_RX = re.compile( + r"(?:(?P€|EUR|USD|\$)\s*(?P\d{1,3}(?:[.,\s]\d{3})*[.,]\d{2}))" + r"|" + r"(?:(?P\d{1,3}(?:[.,\s]\d{3})*[.,]\d{2})\s*(?P€|EUR|USD|\$))", + re.IGNORECASE, +) + +INVOICE_NR_RX = re.compile( + r"(?:rechnungs?\s*-?\s*nr\.?|invoice\s*(?:no|number|#)|beleg\s*nr\.?|" + r"order\s*#?|auftrag\s*\#?)\s*[:#]?\s*" + r"(?P[A-Z0-9][A-Z0-9\-_/]{3,30})", + re.IGNORECASE, +) + + +def _normalize_currency(cur: str) -> str: + cur = cur.upper() + if cur == "$": + return "USD" + if cur == "€": + return "EUR" + return cur + + +def extract_amount(text: str) -> str: + m = AMOUNT_RX.search(text) + if not m: + return "" + num = m.group("num1") or m.group("num2") or "" + cur = m.group("cur1") or m.group("cur2") or "" + return f"{num} {_normalize_currency(cur)}".strip() + + +def extract_invoice_number(text: str) -> str: + m = INVOICE_NR_RX.search(text) + return m.group("nr") if m else "" + + +def detect_portal_hint(text: str) -> str: + low = text.lower() + for hint in PORTAL_HINTS: + if hint in low: + return hint + return "" + + +# ---------------------------------------------------------------------------- +# Sanitization +# ---------------------------------------------------------------------------- + +SAFE_RX = re.compile(r"[^A-Za-z0-9._\-äöüÄÖÜß]+") +CSV_BAD_RX = re.compile(r"[\r\n\t]+") + + +def sanitize(s: str, maxlen: int = 60) -> str: + s = SAFE_RX.sub("_", s).strip("_") + return s[:maxlen] if s else "datei" + + +def csvsafe(s: str) -> str: + """Entfernt Zeilenumbrüche/Tabs aus Feldern, die Excel sonst zerlegen würde.""" + return CSV_BAD_RX.sub(" ", s).strip() + + +# ---------------------------------------------------------------------------- +# Hauptlauf +# ---------------------------------------------------------------------------- + +def run(args: argparse.Namespace) -> int: + out_root = Path(args.output) / args._label + log = setup_logging(out_root, verbose=args.verbose, quiet=args.quiet) + load_user_config() + + seen_path = out_root / "_seen.json" + if seen_path.exists(): + try: + seen: set[str] = set(json.loads(seen_path.read_text(encoding="utf-8"))) + except json.JSONDecodeError: + log.warning("_seen.json defekt – starte mit leerem Cache") + seen = set() + else: + seen = set() + + gezogen: list[GezogeneRechnung] = [] + manuell: list[ManuelleAufgabe] = [] + + log.info("Verbinde %s -> %s:%d", args.email, IMAP_HOST, IMAP_PORT) + password = getpass.getpass("Gmail App-Passwort (Eingabe unsichtbar): ") + + try: + conn = connect(args.email, password, args.mailbox) + except imaplib.IMAP4.error as e: + log.error("Login fehlgeschlagen: %s", e) + return 2 + + try: + log.info("Suche Mails %s bis %s (exklusiv)", args._from, args._to) + uids = search_uids(conn, args._from, args._to) + total = len(uids) + log.info("%d Mails im Zeitraum gefunden", total) + + for i, uid in enumerate(uids, 1): + if i % 50 == 0: + log.info("Progress: %d/%d", i, total) + + msg = fetch_mail_with_retry(conn, uid, log) + if msg is None: + continue + + mail = build_mail_ref(uid, msg, log) + if mail.message_id and mail.message_id in seen: + log.debug("Skip bereits verarbeitet: %s", mail.message_id) + continue + + verdict = classify(mail) + haystack = f"{mail.subject}\n{mail.body_text}" + amount = extract_amount(haystack) + invoice_nr = extract_invoice_number(haystack) + datestr = mail.date.strftime("%Y-%m-%d") + + if verdict == "AUTO": + target_dir = out_root / sanitize(mail.sender_domain or "unbekannt", 40) + target_dir.mkdir(parents=True, exist_ok=True) + for fname, blob, from_zip in mail.pdf_attachments: + safe_subject = sanitize(mail.subject, 50) + safe_orig = sanitize(fname, 60) + out_path = target_dir / f"{datestr}_{safe_subject}_{safe_orig}" + if out_path.suffix.lower() != ".pdf": + out_path = out_path.with_suffix(".pdf") + out_path.write_bytes(blob) + gezogen.append(GezogeneRechnung( + sender_domain=mail.sender_domain, + sender_email=mail.sender_email, + date=datestr, + subject=mail.subject, + amount=amount, + invoice_number=invoice_nr, + file_path=str(out_path.relative_to(out_root)), + from_zip=from_zip, + )) + log.info("AUTO [%d/%d] %s – %s", + i, total, mail.sender_domain, mail.subject[:60]) + + elif verdict == "MANUAL": + manuell.append(ManuelleAufgabe( + sender_domain=mail.sender_domain, + sender_email=mail.sender_email, + date=datestr, + subject=mail.subject, + amount_hint=amount, + portal_hint=detect_portal_hint(haystack), + grund="Rechnungs-Mail ohne PDF-Anhang", + )) + log.info("MANUAL [%d/%d] %s – %s", + i, total, mail.sender_domain, mail.subject[:60]) + else: + log.debug("IGNORE [%d/%d] %s – %s", + i, total, mail.sender_domain, mail.subject[:60]) + + if mail.message_id: + seen.add(mail.message_id) + + finally: + try: + conn.close() + conn.logout() + except (imaplib.IMAP4.error, OSError): + pass + + # ----------- Output ----------- + write_csv( + out_root / "_gezogen.csv", + ["Absender-Domain", "Absender-Email", "Datum", "Betreff", + "Betrag", "Rechnungs-Nr", "Datei", "Aus-ZIP"], + [[csvsafe(g.sender_domain), csvsafe(g.sender_email), g.date, + csvsafe(g.subject), csvsafe(g.amount), csvsafe(g.invoice_number), + csvsafe(g.file_path), "ja" if g.from_zip else "nein"] + for g in gezogen], + ) + + write_csv( + out_root / "_manuell_ziehen.csv", + ["Absender-Domain", "Absender-Email", "Datum", "Betreff", + "Betrag-Hinweis", "Portal-Hinweis", "Grund"], + [[csvsafe(m.sender_domain), csvsafe(m.sender_email), m.date, + csvsafe(m.subject), csvsafe(m.amount_hint), + csvsafe(m.portal_hint), csvsafe(m.grund)] + for m in manuell], + ) + + seen_path.write_text( + json.dumps(sorted(seen), ensure_ascii=False, indent=2), + encoding="utf-8", + ) + + log.info("--- FERTIG ---") + log.info("Gezogen: %d PDFs", len(gezogen)) + log.info("Manuell: %d Mails ohne PDF", len(manuell)) + log.info("Output: %s", out_root.resolve()) + + return 0 + + +def write_csv(path: Path, header: list[str], rows: list[list[str]]) -> None: + with path.open("w", encoding="utf-8", newline="") as f: + w = csv.writer(f, delimiter=";", quoting=csv.QUOTE_MINIMAL) + w.writerow(header) + w.writerows(rows) + + +if __name__ == "__main__": + sys.exit(run(parse_args())) diff --git a/SECURITY.md b/SECURITY.md index 0697697..0d97437 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ ## Supported Versions -NexaSign is currently published as a public beta. Only the latest released tag +NexaFile is currently published as a public beta. Only the latest released tag and the `main` branch receive security fixes. | Version | Supported | @@ -31,7 +31,7 @@ requested. In scope: -- The NexaSign Remix application (`apps/remix/`) +- The NexaFile Remix application (`apps/remix/`) - The PHP template tools under `templates/` (vorlagen-index, av-vertrag-web, x-rechnung-web) - The GoBD tooling under `tools/` and deployment configs under `deploy/` diff --git a/apps/docs/content/docs/compliance/certifications.mdx b/apps/docs/content/docs/compliance/certifications.mdx index 0999e88..b6d06b9 100644 --- a/apps/docs/content/docs/compliance/certifications.mdx +++ b/apps/docs/content/docs/compliance/certifications.mdx @@ -1,6 +1,6 @@ --- title: Certifications & Regulatory Compliance -description: NexaSign's compliance status for industry certifications and regulatory frameworks. +description: NexaFile's compliance status for industry certifications and regulatory frameworks. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -20,7 +20,7 @@ import { Callout } from 'fumadocs-ui/components/callout'; 21 CFR Part 11 is a regulation by the FDA that establishes the criteria for electronic records and electronic signatures to ensure their authenticity, integrity, and confidentiality in the pharmaceutical, medical device, and other FDA-regulated industries. -Read more about [21 CFR Part 11 with NexaSign](https://nexastack.co). +Read more about [21 CFR Part 11 with NexaFile](https://nexastack.co). ### Main Requirements diff --git a/apps/docs/content/docs/compliance/esign.mdx b/apps/docs/content/docs/compliance/esign.mdx index f3f6d64..5309328 100644 --- a/apps/docs/content/docs/compliance/esign.mdx +++ b/apps/docs/content/docs/compliance/esign.mdx @@ -102,9 +102,9 @@ Requirements vary significantly by jurisdiction. Some transactions may require s --- -## How NexaSign Supports Compliance +## How NexaFile Supports Compliance -NexaSign provides features that support compliance with e-signature laws across jurisdictions: +NexaFile provides features that support compliance with e-signature laws across jurisdictions: ### Intent to Sign @@ -139,7 +139,7 @@ NexaSign provides features that support compliance with e-signature laws across ## Audit Trails -NexaSign maintains an audit trail for each document, recording: +NexaFile maintains an audit trail for each document, recording: | Event | Recorded Data | | ------------------ | -------------------------------------- | @@ -154,9 +154,9 @@ The audit trail provides evidence of the signing process, including who signed, --- -## What NexaSign Does NOT Provide +## What NexaFile Does NOT Provide -NexaSign supports compliance with Simple Electronic Signature (SES) requirements. The following are not currently provided: +NexaFile supports compliance with Simple Electronic Signature (SES) requirements. The following are not currently provided: | Capability | Status | | ----------------------------------------- | ------------------------------------------------------------------------------------- | diff --git a/apps/docs/content/docs/compliance/gdpr.mdx b/apps/docs/content/docs/compliance/gdpr.mdx index 567ab01..6b7609b 100644 --- a/apps/docs/content/docs/compliance/gdpr.mdx +++ b/apps/docs/content/docs/compliance/gdpr.mdx @@ -1,19 +1,19 @@ --- title: GDPR -description: Understand how NexaSign handles GDPR compliance for data processing and storage. +description: Understand how NexaFile handles GDPR compliance for data processing and storage. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; -## NexaSign's Role +## NexaFile's Role -When using NexaSign for document signing, two distinct data processing roles apply: +When using NexaFile for document signing, two distinct data processing roles apply: | Role | Description | | ------------------- | ------------------------------------------------------------------------------------- | -| **Data Controller** | You (the organisation using NexaSign) determine the purposes and means of processing | -| **Data Processor** | NexaSign processes personal data on your behalf according to your instructions | +| **Data Controller** | You (the organisation using NexaFile) determine the purposes and means of processing | +| **Data Processor** | NexaFile processes personal data on your behalf according to your instructions | As the data controller, you are responsible for: @@ -22,7 +22,7 @@ As the data controller, you are responsible for: - Responding to data subject access requests - Ensuring compliance with GDPR requirements -As the data processor, NexaSign: +As the data processor, NexaFile: - Processes data only according to your instructions - Implements appropriate security measures @@ -31,7 +31,7 @@ As the data processor, NexaSign: ## Data Processing -NexaSign processes personal data necessary to provide document signing services: +NexaFile processes personal data necessary to provide document signing services: | Data Category | Examples | Purpose | | ------------------ | ---------------------------------------------- | --------------------------------------- | @@ -49,10 +49,10 @@ Data is processed for the following purposes: ## Data Storage Locations -Where your data is stored depends on how you use NexaSign: +Where your data is stored depends on how you use NexaFile: - - + + For the hosted cloud service: @@ -60,15 +60,15 @@ For the hosted cloud service: - Document storage uses EU-based infrastructure - Backups are maintained in geographically separate EU locations -Contact NexaSign for specific information about sub-processors and data centre locations. +Contact NexaFile for specific information about sub-processors and data centre locations. -When you self-host NexaSign: +When you self-host NexaFile: - You control all data storage locations -- No data is transmitted to NexaSign's infrastructure +- No data is transmitted to NexaFile's infrastructure - You choose your own database, file storage, and backup locations Self-hosting provides complete control over data residency, which may be required for certain compliance scenarios. @@ -91,13 +91,13 @@ GDPR grants individuals specific rights regarding their personal data. As the da When you receive a data subject request, you can: -- Export user and document data from your NexaSign account +- Export user and document data from your NexaFile account - Delete user accounts and associated documents -- Contact NexaSign support for assistance with cloud-hosted data +- Contact NexaFile support for assistance with cloud-hosted data ## Data Deletion -NexaSign supports data deletion to help fulfill erasure requests: +NexaFile supports data deletion to help fulfill erasure requests: @@ -124,7 +124,7 @@ NexaSign supports data deletion to help fulfill erasure requests: ## Self-Hosting for GDPR Compliance -Self-hosting NexaSign can simplify GDPR compliance: +Self-hosting NexaFile can simplify GDPR compliance: - **Data residency** - Store all data in your chosen jurisdiction - **Sub-processor control** - No third-party data processors beyond your own infrastructure @@ -137,17 +137,17 @@ See the [Self-Hosting Guide](/docs/self-hosting) for deployment options. A Data Processing Agreement (DPA) is a contract required by GDPR when a data controller engages a data processor. - - + + - A DPA is available upon request - Contact [info@nexastack.co](mailto:info@nexastack.co) to request a DPA -- The DPA covers NexaSign's obligations as a data processor +- The DPA covers NexaFile's obligations as a data processor -No DPA with NexaSign is required since no personal data is processed by NexaSign. +No DPA with NexaFile is required since no personal data is processed by NexaFile. @@ -156,7 +156,7 @@ No DPA with NexaSign is required since no personal data is processed by NexaSign ## Disclaimer -This documentation is provided for informational purposes only and does not constitute legal advice. GDPR compliance depends on your specific circumstances, including how you use NexaSign, what data you process, and your organisation's obligations. +This documentation is provided for informational purposes only and does not constitute legal advice. GDPR compliance depends on your specific circumstances, including how you use NexaFile, what data you process, and your organisation's obligations. Consult with qualified legal counsel to: @@ -170,5 +170,5 @@ Consult with qualified legal counsel to: ## Related - [Standards & Regulations](/docs/compliance/standards) - eIDAS, ESIGN Act, and other compliance frameworks -- [Self-Hosting Guide](/docs/self-hosting) - Deploy NexaSign on your own infrastructure +- [Self-Hosting Guide](/docs/self-hosting) - Deploy NexaFile on your own infrastructure - [Security Settings](/docs/users/settings/security) - Configure authentication and security options diff --git a/apps/docs/content/docs/compliance/index.mdx b/apps/docs/content/docs/compliance/index.mdx index 0c89d86..78bf2d3 100644 --- a/apps/docs/content/docs/compliance/index.mdx +++ b/apps/docs/content/docs/compliance/index.mdx @@ -53,6 +53,6 @@ Consult with qualified legal counsel to determine the specific requirements for ## Related -- [Privacy Policy](/docs/policies/privacy) - How NexaSign handles personal data +- [Privacy Policy](/docs/policies/privacy) - How NexaFile handles personal data - [Security](/docs/policies/security) - Security practices and measures -- [Terms of Service](/docs/policies/terms) - Terms governing use of NexaSign +- [Terms of Service](/docs/policies/terms) - Terms governing use of NexaFile diff --git a/apps/docs/content/docs/compliance/signature-levels.mdx b/apps/docs/content/docs/compliance/signature-levels.mdx index 1951a1e..b103313 100644 --- a/apps/docs/content/docs/compliance/signature-levels.mdx +++ b/apps/docs/content/docs/compliance/signature-levels.mdx @@ -7,7 +7,7 @@ import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; import { Callout } from 'fumadocs-ui/components/callout'; - NexaSign seals all signed documents cryptographically, regardless of signature level, to prevent + NexaFile seals all signed documents cryptographically, regardless of signature level, to prevent any alterations after signing. @@ -184,9 +184,9 @@ Certain transactions require or benefit from QES: --- -## What NexaSign Provides +## What NexaFile Provides -NexaSign supports Simple Electronic Signatures (SES) with features that enhance evidentiary value: +NexaFile supports Simple Electronic Signatures (SES) with features that enhance evidentiary value: ### SES Features @@ -201,7 +201,7 @@ NexaSign supports Simple Electronic Signatures (SES) with features that enhance - **Access Codes** - Require signers to enter a code before accessing documents - **Signing Order** - Control the sequence of signatures -### What NexaSign Does Not Provide +### What NexaFile Does Not Provide | Capability | Status | | ----------------------------------------- | --------------------------------------------------------- | diff --git a/apps/docs/content/docs/compliance/standards.mdx b/apps/docs/content/docs/compliance/standards.mdx index 23e50cd..2037290 100644 --- a/apps/docs/content/docs/compliance/standards.mdx +++ b/apps/docs/content/docs/compliance/standards.mdx @@ -88,9 +88,9 @@ Timestamps serve two purposes in document signing: Without a trusted timestamp, a signature can only be verified while the signing certificate remains valid. With a timestamp, the signature remains verifiable as long as the timestamp can be validated. -## What NexaSign Implements +## What NexaFile Implements -NexaSign implements digital signatures with the following characteristics: +NexaFile implements digital signatures with the following characteristics: - **PDF signatures**: Documents are signed using the PDF signature capabilities defined in ISO 32000 - **X.509 certificates**: Signatures use X.509 certificates for signer identification diff --git a/apps/docs/content/docs/concepts/index.mdx b/apps/docs/content/docs/concepts/index.mdx index 3568d2b..cad490f 100644 --- a/apps/docs/content/docs/concepts/index.mdx +++ b/apps/docs/content/docs/concepts/index.mdx @@ -37,7 +37,7 @@ description: Foundational concepts behind document signing, recipient roles, fie ## How These Concepts Apply -These concepts work consistently across all ways you interact with NexaSign: +These concepts work consistently across all ways you interact with NexaFile: - **Web application**: When you create documents in the UI, you'll select recipient roles, add fields, and track documents through their lifecycle states. diff --git a/apps/docs/content/docs/concepts/signing-certificates.mdx b/apps/docs/content/docs/concepts/signing-certificates.mdx index 9493f67..186f515 100644 --- a/apps/docs/content/docs/concepts/signing-certificates.mdx +++ b/apps/docs/content/docs/concepts/signing-certificates.mdx @@ -1,15 +1,15 @@ --- title: Signing Certificates -description: NexaSign digitally signs completed documents using X.509 certificates, providing cryptographic proof of authenticity and integrity. +description: NexaFile digitally signs completed documents using X.509 certificates, providing cryptographic proof of authenticity and integrity. --- import { Callout } from 'fumadocs-ui/components/callout'; import { Step, Steps } from 'fumadocs-ui/components/steps'; import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; -## How NexaSign Signs Documents +## How NexaFile Signs Documents -NexaSign applies a digital signature to the PDF when all recipients complete their actions. +NexaFile applies a digital signature to the PDF when all recipients complete their actions. {/* prettier-ignore */} @@ -44,13 +44,13 @@ The digital signature provides two guarantees: | Guarantee | Description | | ---------------- | -------------------------------------------------------------------------- | | **Integrity** | The document has not been altered since signing | -| **Authenticity** | The document was signed by the certificate holder (the NexaSign instance) | +| **Authenticity** | The document was signed by the certificate holder (the NexaFile instance) | If anyone modifies the PDF after signing, the signature becomes invalid. PDF readers will display a warning that the document has been changed. ## Timestamps -NexaSign can include a trusted timestamp from a Time Stamping Authority (TSA) in the signature. This proves when the document was signed, independent of the signer's system clock. Timestamps are important for: +NexaFile can include a trusted timestamp from a Time Stamping Authority (TSA) in the signature. This proves when the document was signed, independent of the signer's system clock. Timestamps are important for: - Legal evidence of when signing occurred - Long-term validation (LTV) of signatures @@ -89,13 +89,13 @@ PDF readers validate signatures against their list of trusted Certificate Author A self-signed certificate still provides integrity verification. The document cannot be modified without invalidating the signature. The warning only indicates that a third-party CA has not verified the certificate issuer's identity. -For most use cases, self-signed certificates are sufficient. The signature still proves the document came from your NexaSign instance and has not been tampered with. +For most use cases, self-signed certificates are sufficient. The signature still proves the document came from your NexaFile instance and has not been tampered with. ## Using Custom Certificates -If you self-host NexaSign, you can use your own signing certificate. +If you self-host NexaFile, you can use your own signing certificate. diff --git a/apps/docs/content/docs/concepts/signing-workflow.mdx b/apps/docs/content/docs/concepts/signing-workflow.mdx index f009a6f..e44545a 100644 --- a/apps/docs/content/docs/concepts/signing-workflow.mdx +++ b/apps/docs/content/docs/concepts/signing-workflow.mdx @@ -190,7 +190,7 @@ Once all recipients with required actions have completed them, the document is f ## Workflow Variations -NexaSign supports several workflow variations to handle different signing scenarios. +NexaFile supports several workflow variations to handle different signing scenarios. diff --git a/apps/docs/content/docs/developers/api/developer-mode.mdx b/apps/docs/content/docs/developers/api/developer-mode.mdx index 50a5c52..f1f132c 100644 --- a/apps/docs/content/docs/developers/api/developer-mode.mdx +++ b/apps/docs/content/docs/developers/api/developer-mode.mdx @@ -1,11 +1,11 @@ --- title: Developer Mode -description: Advanced development tools for debugging field IDs, recipient IDs, coordinates and integrating with the NexaSign API. +description: Advanced development tools for debugging field IDs, recipient IDs, coordinates and integrating with the NexaFile API. --- ## Overview -Developer mode provides additional tools and features to help you integrate and debug NexaSign. +Developer mode provides additional tools and features to help you integrate and debug NexaFile. ## Field Information diff --git a/apps/docs/content/docs/developers/api/documents.mdx b/apps/docs/content/docs/developers/api/documents.mdx index 87076cd..7ea18ee 100644 --- a/apps/docs/content/docs/developers/api/documents.mdx +++ b/apps/docs/content/docs/developers/api/documents.mdx @@ -13,7 +13,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Overview -[Documents](/docs/users/documents) (called "envelopes" in the API) are the core resource in NexaSign. You can: +[Documents](/docs/users/documents) (called "envelopes" in the API) are the core resource in NexaFile. You can: 1. create documents with recipients and fields 2. send them for signing diff --git a/apps/docs/content/docs/developers/api/fields.mdx b/apps/docs/content/docs/developers/api/fields.mdx index 416698c..527921b 100644 --- a/apps/docs/content/docs/developers/api/fields.mdx +++ b/apps/docs/content/docs/developers/api/fields.mdx @@ -469,7 +469,7 @@ const field = { ## Placeholder-Based Field Positioning -Instead of specifying exact coordinates, you can position fields using placeholder text embedded in your PDF. Include placeholder markers such as `{{signature, r1}}` in your document, and NexaSign will create fields at those locations when the document is uploaded. +Instead of specifying exact coordinates, you can position fields using placeholder text embedded in your PDF. Include placeholder markers such as `{{signature, r1}}` in your document, and NexaFile will create fields at those locations when the document is uploaded. This approach is useful when generating PDFs programmatically or using templates with consistent layouts. diff --git a/apps/docs/content/docs/developers/api/index.mdx b/apps/docs/content/docs/developers/api/index.mdx index 804ce0e..eeb61af 100644 --- a/apps/docs/content/docs/developers/api/index.mdx +++ b/apps/docs/content/docs/developers/api/index.mdx @@ -1,6 +1,6 @@ --- title: API Reference -description: Complete reference for the NexaSign REST API. +description: Complete reference for the NexaFile REST API. --- import { Callout } from 'fumadocs-ui/components/callout'; diff --git a/apps/docs/content/docs/developers/api/rate-limits.mdx b/apps/docs/content/docs/developers/api/rate-limits.mdx index 04bc7a9..18db5e4 100644 --- a/apps/docs/content/docs/developers/api/rate-limits.mdx +++ b/apps/docs/content/docs/developers/api/rate-limits.mdx @@ -1,13 +1,13 @@ --- title: Rate Limits -description: Learn about the rate limits for the NexaSign Public API. +description: Learn about the rate limits for the NexaFile Public API. --- import { Callout } from 'fumadocs-ui/components/callout'; ## Overview -NexaSign enforces rate limits on all API endpoints to ensure service stability. +NexaFile enforces rate limits on all API endpoints to ensure service stability. ## HTTP Rate Limits diff --git a/apps/docs/content/docs/developers/api/teams.mdx b/apps/docs/content/docs/developers/api/teams.mdx index 3f6db7e..305da6d 100644 --- a/apps/docs/content/docs/developers/api/teams.mdx +++ b/apps/docs/content/docs/developers/api/teams.mdx @@ -42,7 +42,7 @@ A team object contains the following properties: ## Team-Scoped API Tokens -API tokens in NexaSign are always scoped to a specific team. When you create an API token, it is associated with the team you're currently working in. +API tokens in NexaFile are always scoped to a specific team. When you create an API token, it is associated with the team you're currently working in. ### How Team Scoping Works diff --git a/apps/docs/content/docs/developers/api/versioning.mdx b/apps/docs/content/docs/developers/api/versioning.mdx index b14ef07..791b932 100644 --- a/apps/docs/content/docs/developers/api/versioning.mdx +++ b/apps/docs/content/docs/developers/api/versioning.mdx @@ -1,13 +1,13 @@ --- title: API Versioning -description: Versioning information for the NexaSign public API. +description: Versioning information for the NexaFile public API. --- import { Callout } from 'fumadocs-ui/components/callout'; ## Overview -NexaSign uses API versioning to manage changes to the public API. This allows us to introduce new features, fix bugs, and make other changes without breaking existing integrations. +NexaFile uses API versioning to manage changes to the public API. This allows us to introduce new features, fix bugs, and make other changes without breaking existing integrations. The current version of the API is `v2`. diff --git a/apps/docs/content/docs/developers/contributing/contributing-translations.mdx b/apps/docs/content/docs/developers/contributing/contributing-translations.mdx index 138d576..5455823 100644 --- a/apps/docs/content/docs/developers/contributing/contributing-translations.mdx +++ b/apps/docs/content/docs/developers/contributing/contributing-translations.mdx @@ -1,6 +1,6 @@ --- title: Contributing Translations -description: Learn how to contribute translations to NexaSign and become part of our community. +description: Learn how to contribute translations to NexaFile and become part of our community. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -25,8 +25,8 @@ Each PO file contains translations which look like this: ```po #: apps/remix/app/(signing)/sign/[token]/no-longer-available.tsx:61 -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "Möchten Sie auffällige Signatur-Links wie diesen senden? <0>Überprüfen Sie NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "Möchten Sie auffällige Signatur-Links wie diesen senden? <0>Überprüfen Sie NexaFile." ``` - `msgid`: The original text in English (never edit this manually) @@ -83,7 +83,7 @@ If you want to add translations for a language that doesn't exist yet: If you have any questions, hop into our [Discord](https://github.com/NexaStack-Software/NexaSign/discussions) and ask us directly! -Thank you for helping make NexaSign more accessible to users around the world! +Thank you for helping make NexaFile more accessible to users around the world! ## See Also diff --git a/apps/docs/content/docs/developers/contributing/index.mdx b/apps/docs/content/docs/developers/contributing/index.mdx index c8e5721..1e86c56 100644 --- a/apps/docs/content/docs/developers/contributing/index.mdx +++ b/apps/docs/content/docs/developers/contributing/index.mdx @@ -1,6 +1,6 @@ --- -title: Contributing to NexaSign -description: Learn how to contribute to NexaSign and become part of our community. +title: Contributing to NexaFile +description: Learn how to contribute to NexaFile and become part of our community. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -8,9 +8,9 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Overview -If you plan to contribute to NexaSign, please take a moment to feel awesome. People like you are what open source is about. Any contributions, no matter how big or small, are highly appreciated. +If you plan to contribute to NexaFile, please take a moment to feel awesome. People like you are what open source is about. Any contributions, no matter how big or small, are highly appreciated. -This guide will help you get started with contributing to NexaSign. +This guide will help you get started with contributing to NexaFile. ## Before Getting Started @@ -71,7 +71,7 @@ The development branch is `main`, and all pull requests should be made against t -### Set up NexaSign locally +### Set up NexaFile locally To set up your local environment, check out the [local development](/docs/developers/local-development) guide. @@ -149,4 +149,4 @@ Once the project builds successfully, you can push your code changes or create a ## See Also - [Local Development](/docs/developers/local-development) - Set up your development environment -- [Contributing Translations](/docs/developers/contributing/contributing-translations) - Help translate NexaSign +- [Contributing Translations](/docs/developers/contributing/contributing-translations) - Help translate NexaFile diff --git a/apps/docs/content/docs/developers/embedding/authoring/index.mdx b/apps/docs/content/docs/developers/embedding/authoring/index.mdx index faf524d..c4c2133 100644 --- a/apps/docs/content/docs/developers/embedding/authoring/index.mdx +++ b/apps/docs/content/docs/developers/embedding/authoring/index.mdx @@ -5,7 +5,7 @@ description: Embed document, template, and envelope creation directly in your ap import { Callout } from 'fumadocs-ui/components/callout'; -In addition to embedding signing, NexaSign supports embedded authoring. It allows your users to create and edit documents, templates, and envelopes without leaving your application. +In addition to embedding signing, NexaFile supports embedded authoring. It allows your users to create and edit documents, templates, and envelopes without leaving your application. Embedded authoring is included with [Enterprise](https://nexastack.co) plans. It is @@ -38,7 +38,7 @@ Before using any authoring component, obtain a presign token from your backend: POST /api/v2/embedding/create-presign-token ``` -This endpoint requires your NexaSign API key. The token has a default expiration of 1 hour. +This endpoint requires your NexaFile API key. The token has a default expiration of 1 hour. See the [API documentation](https://nexasign.nexastack.co/api/v2/openapi.json/reference#tag/embedding) for full details. diff --git a/apps/docs/content/docs/developers/embedding/direct-links.mdx b/apps/docs/content/docs/developers/embedding/direct-links.mdx index 4ecc1cd..ed41d9f 100644 --- a/apps/docs/content/docs/developers/embedding/direct-links.mdx +++ b/apps/docs/content/docs/developers/embedding/direct-links.mdx @@ -24,7 +24,7 @@ Direct links are unique URLs tied to a template that allow anyone to: -When someone uses a direct link, NexaSign creates a new document from the template with that person as the signer. +When someone uses a direct link, NexaFile creates a new document from the template with that person as the signer. ### When to Use Direct Links @@ -286,7 +286,7 @@ Direct links can require authentication before signing. Configure this in your t | Auth Type | Description | | --------- | ---------------------------------------------- | | None | Anyone with the link can sign | -| Account | Signer must be logged into a NexaSign account | +| Account | Signer must be logged into a NexaFile account | To require authentication, set `globalAccessAuth` when creating or updating the template: @@ -397,7 +397,7 @@ const response = await fetch(`${BASE_URL}/template/update`, { ### White-labeling -Enterprise plans support white-label embedding with the "Powered by NexaSign" badge removed. [Contact sales](mailto:info@nexastack.co) for details. +Enterprise plans support white-label embedding with the "Powered by NexaFile" badge removed. [Contact sales](mailto:info@nexastack.co) for details. --- diff --git a/apps/docs/content/docs/developers/embedding/index.mdx b/apps/docs/content/docs/developers/embedding/index.mdx index 5f77475..54095a1 100644 --- a/apps/docs/content/docs/developers/embedding/index.mdx +++ b/apps/docs/content/docs/developers/embedding/index.mdx @@ -8,7 +8,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Embedded Signing vs Embedded Authoring -NexaSign offers two types of embedding: +NexaFile offers two types of embedding: - **Embedded Signing** lets you embed the signing experience in your application. Your users sign documents without leaving your site. Available on Teams Plan and above. - **Embedded Authoring** lets you embed document and template _creation and editing_ in your application. This is an [Enterprise](/docs/policies/enterprise-edition) feature (also available as a Platform Plan add-on). See the [Authoring](/docs/developers/embedding/authoring) guide. @@ -25,7 +25,7 @@ The [Platform Plan](https://nexastack.co) adds enhanced customization: - Custom CSS and styling variables - Dark mode controls -- Removal of NexaSign branding +- Removal of NexaFile branding --- @@ -81,7 +81,7 @@ import { EmbedSignDocument } from '@nexasign/embed-react'; {/* prettier-ignore */} -Navigate to your team's templates in NexaSign +Navigate to your team's templates in NexaFile ![Team Templates](/embedding/team-templates.png) @@ -152,7 +152,7 @@ If you prefer not to use any SDK, you can embed signing using [Direct Links](/do | Prop | Type | Description | | --------------------- | ---------- | ---------------------------------------------------------------- | | `token` | `string` | **Required.** The direct template token. | -| `host` | `string` | NexaSign instance URL. Defaults to `https://nexasign.nexastack.co`. | +| `host` | `string` | NexaFile instance URL. Defaults to `https://nexasign.nexastack.co`. | | `name` | `string` | Pre-fill the signer's name. | | `lockName` | `boolean` | Prevent the signer from changing their name. | | `email` | `string` | Pre-fill the signer's email. | @@ -173,7 +173,7 @@ If you prefer not to use any SDK, you can embed signing using [Direct Links](/do | Prop | Type | Description | | --------------------- | ---------- | ---------------------------------------------------------------- | | `token` | `string` | **Required.** The recipient's signing token. | -| `host` | `string` | NexaSign instance URL. Defaults to `https://nexasign.nexastack.co`. | +| `host` | `string` | NexaFile instance URL. Defaults to `https://nexasign.nexastack.co`. | | `name` | `string` | Pre-fill the signer's name. | | `lockName` | `boolean` | Prevent the signer from changing their name. | | `language` | `string` | Set the UI language. See [Supported Languages](https://github.com/NexaStack-Software/NexaSign/tree/main/packages/lib/constants/locales.ts). | diff --git a/apps/docs/content/docs/developers/embedding/sdks/angular.mdx b/apps/docs/content/docs/developers/embedding/sdks/angular.mdx index af57374..d3d78df 100644 --- a/apps/docs/content/docs/developers/embedding/sdks/angular.mdx +++ b/apps/docs/content/docs/developers/embedding/sdks/angular.mdx @@ -1,6 +1,6 @@ --- title: Angular -description: Embed NexaSign signing in your Angular application using the official SDK. +description: Embed NexaFile signing in your Angular application using the official SDK. --- import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; diff --git a/apps/docs/content/docs/developers/embedding/sdks/preact.mdx b/apps/docs/content/docs/developers/embedding/sdks/preact.mdx index 92fe39c..1142b21 100644 --- a/apps/docs/content/docs/developers/embedding/sdks/preact.mdx +++ b/apps/docs/content/docs/developers/embedding/sdks/preact.mdx @@ -1,6 +1,6 @@ --- title: Preact -description: Embed NexaSign signing in your Preact application using the official SDK. +description: Embed NexaFile signing in your Preact application using the official SDK. --- import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; diff --git a/apps/docs/content/docs/developers/embedding/sdks/react.mdx b/apps/docs/content/docs/developers/embedding/sdks/react.mdx index 883454c..523eaf5 100644 --- a/apps/docs/content/docs/developers/embedding/sdks/react.mdx +++ b/apps/docs/content/docs/developers/embedding/sdks/react.mdx @@ -1,6 +1,6 @@ --- title: React -description: Embed NexaSign signing in your React application using the official SDK. +description: Embed NexaFile signing in your React application using the official SDK. --- import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; diff --git a/apps/docs/content/docs/developers/embedding/sdks/solid.mdx b/apps/docs/content/docs/developers/embedding/sdks/solid.mdx index 8956a2c..5316c8a 100644 --- a/apps/docs/content/docs/developers/embedding/sdks/solid.mdx +++ b/apps/docs/content/docs/developers/embedding/sdks/solid.mdx @@ -1,6 +1,6 @@ --- title: Solid -description: Embed NexaSign signing in your Solid application using the official SDK. +description: Embed NexaFile signing in your Solid application using the official SDK. --- import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; diff --git a/apps/docs/content/docs/developers/embedding/sdks/svelte.mdx b/apps/docs/content/docs/developers/embedding/sdks/svelte.mdx index f94ea5a..ebbfad3 100644 --- a/apps/docs/content/docs/developers/embedding/sdks/svelte.mdx +++ b/apps/docs/content/docs/developers/embedding/sdks/svelte.mdx @@ -1,6 +1,6 @@ --- title: Svelte -description: Embed NexaSign signing in your Svelte application using the official SDK. +description: Embed NexaFile signing in your Svelte application using the official SDK. --- import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; diff --git a/apps/docs/content/docs/developers/embedding/sdks/vue.mdx b/apps/docs/content/docs/developers/embedding/sdks/vue.mdx index d0173e7..3f93609 100644 --- a/apps/docs/content/docs/developers/embedding/sdks/vue.mdx +++ b/apps/docs/content/docs/developers/embedding/sdks/vue.mdx @@ -1,6 +1,6 @@ --- title: Vue -description: Embed NexaSign signing in your Vue application using the official SDK. +description: Embed NexaFile signing in your Vue application using the official SDK. --- import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; diff --git a/apps/docs/content/docs/developers/examples/common-workflows.mdx b/apps/docs/content/docs/developers/examples/common-workflows.mdx index 1c7786d..55b2395 100644 --- a/apps/docs/content/docs/developers/examples/common-workflows.mdx +++ b/apps/docs/content/docs/developers/examples/common-workflows.mdx @@ -750,7 +750,7 @@ app.listen(3000, () => console.log('Webhook server running on port 3000')); ### Register the Webhook -Register your endpoint in the NexaSign dashboard: +Register your endpoint in the NexaFile dashboard: {/* prettier-ignore */} @@ -1037,14 +1037,14 @@ type ApiError = { details?: Record; }; -class NexaSignApiError extends Error { +class NexaFileApiError extends Error { code?: string; statusCode: number; details?: Record; constructor(error: ApiError) { super(error.message); - this.name = 'NexaSignApiError'; + this.name = 'NexaFileApiError'; this.code = error.code; this.statusCode = error.statusCode; this.details = error.details; @@ -1054,7 +1054,7 @@ class NexaSignApiError extends Error { async function handleApiResponse(response: Response): Promise { if (!response.ok) { const error = await response.json(); - throw new NexaSignApiError({ + throw new NexaFileApiError({ message: error.message || 'Unknown error', code: error.code, statusCode: response.status, @@ -1076,7 +1076,7 @@ try { const envelope = await handleApiResponse<{ id: string }>(response); console.log('Created:', envelope.id); } catch (error) { - if (error instanceof NexaSignApiError) { + if (error instanceof NexaFileApiError) { switch (error.statusCode) { case 400: console.error('Invalid request:', error.message); diff --git a/apps/docs/content/docs/developers/getting-started/authentication.mdx b/apps/docs/content/docs/developers/getting-started/authentication.mdx index 4d64177..777ff1c 100644 --- a/apps/docs/content/docs/developers/getting-started/authentication.mdx +++ b/apps/docs/content/docs/developers/getting-started/authentication.mdx @@ -9,8 +9,8 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Prerequisites -- A NexaSign account (cloud or self-hosted) -- A NexaSign account on any plan (Free, Individual, Team, or Enterprise) +- A NexaFile account (cloud or self-hosted) +- A NexaFile account on any plan (Free, Individual, Team, or Enterprise) Free accounts include API access with a limit of 5 documents per month. [Upgrade to a paid @@ -24,7 +24,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ### Open settings -- Log in to your NexaSign account +- Log in to your NexaFile account - Click your avatar in the top right corner - Select **Settings** from the dropdown menu @@ -92,12 +92,12 @@ const documents = await response.json(); ### Using the TypeScript SDK -NexaSign provides official SDKs that handle authentication for you: +NexaFile provides official SDKs that handle authentication for you: ```typescript -import { NexaSign } from '@nexasign/sdk-typescript'; +import { NexaFile } from '@nexasign/sdk-typescript'; -const client = new NexaSign({ +const client = new NexaFile({ apiKey: 'api_xxxxxxxxxxxxxxxx', }); @@ -146,7 +146,7 @@ NEXASIGN_API_KEY=api_xxxxxxxxxxxxxxxx ``` ```typescript -const client = new NexaSign({ +const client = new NexaFile({ apiKey: process.env.NEXASIGN_API_KEY, }); ``` diff --git a/apps/docs/content/docs/developers/getting-started/first-api-call.mdx b/apps/docs/content/docs/developers/getting-started/first-api-call.mdx index e59ae59..f2657fa 100644 --- a/apps/docs/content/docs/developers/getting-started/first-api-call.mdx +++ b/apps/docs/content/docs/developers/getting-started/first-api-call.mdx @@ -1,6 +1,6 @@ --- title: First API Call -description: Create and send a document for signing using the NexaSign API, from uploading a PDF to adding recipients and distributing for signature. +description: Create and send a document for signing using the NexaFile API, from uploading a PDF to adding recipients and distributing for signature. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -11,7 +11,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; Before starting, you need: -- A NexaSign account (cloud or self-hosted) +- A NexaFile account (cloud or self-hosted) - An API token ([create one in team settings](/docs/developers/getting-started/authentication)) - A PDF file to send for signing diff --git a/apps/docs/content/docs/developers/index.mdx b/apps/docs/content/docs/developers/index.mdx index 3be5153..0ab3dfb 100644 --- a/apps/docs/content/docs/developers/index.mdx +++ b/apps/docs/content/docs/developers/index.mdx @@ -1,6 +1,6 @@ --- title: Developer Guide -description: Integrate NexaSign into your applications using the REST API, webhooks, and embedding options. +description: Integrate NexaFile into your applications using the REST API, webhooks, and embedding options. --- ## Getting Started @@ -81,7 +81,7 @@ Official SDKs are available for multiple languages: /> diff --git a/apps/docs/content/docs/developers/local-development/gitpod.mdx b/apps/docs/content/docs/developers/local-development/gitpod.mdx index 8a1c106..a9c11c7 100644 --- a/apps/docs/content/docs/developers/local-development/gitpod.mdx +++ b/apps/docs/content/docs/developers/local-development/gitpod.mdx @@ -1,6 +1,6 @@ --- title: Run in Gitpod -description: Get started with NexaSign in a ready-to-use Gitpod workspace in your browser. +description: Get started with NexaFile in a ready-to-use Gitpod workspace in your browser. --- Click below to launch a ready-to-use Gitpod workspace in your browser. diff --git a/apps/docs/content/docs/developers/local-development/index.mdx b/apps/docs/content/docs/developers/local-development/index.mdx index 80737d8..f9c0531 100644 --- a/apps/docs/content/docs/developers/local-development/index.mdx +++ b/apps/docs/content/docs/developers/local-development/index.mdx @@ -1,11 +1,11 @@ --- title: Local Development -description: Learn how to set up NexaSign for local development. +description: Learn how to set up NexaFile for local development. --- ## Overview -There are multiple ways of setting up NexaSign for local development. At the moment of writing this documentation, there are 3 ways of running NexaSign locally: +There are multiple ways of setting up NexaFile for local development. At the moment of writing this documentation, there are 3 ways of running NexaFile locally: - [Using the developer quickstart with Docker](/docs/developers/local-development/quickstart) - [Manually setting up the development environment](/docs/developers/local-development/manual) @@ -31,7 +31,7 @@ Pick the one that fits your needs the best. Join NexaSign on Discord @@ -62,5 +62,5 @@ Pick the one that fits your needs the best. ## See Also -- [Contributing](/docs/developers/contributing) - Learn how to contribute to NexaSign +- [Contributing](/docs/developers/contributing) - Learn how to contribute to NexaFile - [Self-Hosting](/docs/self-hosting) - Deploy your own instance diff --git a/apps/docs/content/docs/developers/local-development/manual.mdx b/apps/docs/content/docs/developers/local-development/manual.mdx index cc908af..cf7874d 100644 --- a/apps/docs/content/docs/developers/local-development/manual.mdx +++ b/apps/docs/content/docs/developers/local-development/manual.mdx @@ -1,6 +1,6 @@ --- title: Manual Setup -description: Manually set up NexaSign on your machine for local development. +description: Manually set up NexaFile on your machine for local development. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -8,15 +8,15 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; # Manual Setup -Follow these steps to set up NexaSign on your local machine: +Follow these steps to set up NexaFile on your local machine: {/* prettier-ignore */} -### Fork NexaSign +### Fork NexaFile -Fork the [NexaSign repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks) to your GitHub account. +Fork the [NexaFile repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks) to your GitHub account. @@ -93,7 +93,7 @@ Run `npm run dev` in the root directory to start the application. ### Access the application -Access the NexaSign application by visiting `http://localhost:3000` in your web browser. +Access the NexaFile application by visiting `http://localhost:3000` in your web browser. diff --git a/apps/docs/content/docs/developers/local-development/quickstart.mdx b/apps/docs/content/docs/developers/local-development/quickstart.mdx index ed82a57..3dc13a9 100644 --- a/apps/docs/content/docs/developers/local-development/quickstart.mdx +++ b/apps/docs/content/docs/developers/local-development/quickstart.mdx @@ -1,6 +1,6 @@ --- title: Developer Quickstart -description: Quickly set up NexaSign on your machine for local development with Docker and Docker Compose. +description: Quickly set up NexaFile on your machine for local development with Docker and Docker Compose. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -19,9 +19,9 @@ Want to get up and running quickly? Follow these steps: -### Fork NexaSign +### Fork NexaFile -Fork the [NexaSign repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks) to your GitHub account. +Fork the [NexaFile repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/about-forks) to your GitHub account. diff --git a/apps/docs/content/docs/developers/local-development/translations.mdx b/apps/docs/content/docs/developers/local-development/translations.mdx index b80724b..b57d264 100644 --- a/apps/docs/content/docs/developers/local-development/translations.mdx +++ b/apps/docs/content/docs/developers/local-development/translations.mdx @@ -5,7 +5,7 @@ description: Handling translations in code. ## Overview -NexaSign uses the following stack to handle translations: +NexaFile uses the following stack to handle translations: - [Lingui](https://lingui.dev/) - React i10n library - [Crowdin](https://crowdin.com/) - Handles syncing translations @@ -90,4 +90,4 @@ export const SomeComponent = () => { ## See Also -- [Contributing Translations](/docs/developers/contributing/contributing-translations) - Help translate NexaSign +- [Contributing Translations](/docs/developers/contributing/contributing-translations) - Help translate NexaFile diff --git a/apps/docs/content/docs/developers/meta.json b/apps/docs/content/docs/developers/meta.json index a70fa6d..18b12ec 100644 --- a/apps/docs/content/docs/developers/meta.json +++ b/apps/docs/content/docs/developers/meta.json @@ -1,6 +1,6 @@ { "title": "Developers", - "description": "Integrate with NexaSign", + "description": "Integrate with NexaFile", "root": true, "pages": [ "getting-started", diff --git a/apps/docs/content/docs/developers/webhooks/index.mdx b/apps/docs/content/docs/developers/webhooks/index.mdx index 1a186a7..4982797 100644 --- a/apps/docs/content/docs/developers/webhooks/index.mdx +++ b/apps/docs/content/docs/developers/webhooks/index.mdx @@ -5,11 +5,11 @@ description: Receive real-time notifications for document and template events. ## How Webhooks Work -1. You configure a webhook URL in NexaSign -2. When an event occurs, NexaSign sends an HTTP POST to your URL +1. You configure a webhook URL in NexaFile +2. When an event occurs, NexaFile sends an HTTP POST to your URL 3. Your application processes the event and responds with 200 OK -NexaSign supports webhook events for the full document lifecycle (created, sent, opened, signed, completed, rejected, cancelled) as well as template events (created, updated, deleted, used). +NexaFile supports webhook events for the full document lifecycle (created, sent, opened, signed, completed, rejected, cancelled) as well as template events (created, updated, deleted, used). --- diff --git a/apps/docs/content/docs/developers/webhooks/setup.mdx b/apps/docs/content/docs/developers/webhooks/setup.mdx index a1a2e06..9b1d940 100644 --- a/apps/docs/content/docs/developers/webhooks/setup.mdx +++ b/apps/docs/content/docs/developers/webhooks/setup.mdx @@ -10,7 +10,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Overview -Webhooks are HTTP callbacks triggered by specific events in NexaSign. When an event occurs (such as a document being signed), NexaSign sends an HTTP POST request to your configured URL with details about the event. +Webhooks are HTTP callbacks triggered by specific events in NexaFile. When an event occurs (such as a document being signed), NexaFile sends an HTTP POST request to your configured URL with details about the event. Common use cases include: @@ -25,7 +25,7 @@ Common use cases include: ## Creating a Webhook Endpoint -Before configuring a webhook in NexaSign, you need an endpoint that can receive HTTP POST requests. Here's a minimal example: +Before configuring a webhook in NexaFile, you need an endpoint that can receive HTTP POST requests. Here's a minimal example: @@ -148,10 +148,10 @@ func main() { - Always respond with a `200 OK` status within 30 seconds. NexaSign will retry failed deliveries. + Always respond with a `200 OK` status within 30 seconds. NexaFile will retry failed deliveries. -## Configuring Webhooks in NexaSign via the Dashboard +## Configuring Webhooks in NexaFile via the Dashboard {/* prettier-ignore */} @@ -238,7 +238,7 @@ See [Webhook Events](/docs/developers/webhooks/events) for detailed payload info ## Testing Webhooks -NexaSign provides a built-in testing feature to verify your webhook endpoint works correctly. +NexaFile provides a built-in testing feature to verify your webhook endpoint works correctly. {/* prettier-ignore */} @@ -312,13 +312,13 @@ Navigate to the webhook call details page Click the **Resend** button -NexaSign will attempt to deliver the same payload again +NexaFile will attempt to deliver the same payload again ## Retry Policy -When a webhook delivery fails (non-2xx response or timeout), NexaSign automatically retries with exponential backoff: +When a webhook delivery fails (non-2xx response or timeout), NexaFile automatically retries with exponential backoff: | Attempt | Delay | | ------- | ----- | diff --git a/apps/docs/content/docs/developers/webhooks/verification.mdx b/apps/docs/content/docs/developers/webhooks/verification.mdx index 286fdd3..19e47da 100644 --- a/apps/docs/content/docs/developers/webhooks/verification.mdx +++ b/apps/docs/content/docs/developers/webhooks/verification.mdx @@ -10,11 +10,11 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Overview -Verifying webhook requests ensures that incoming payloads originate from NexaSign and have not been tampered with. Without verification, attackers could forge requests to your endpoint and trigger unintended actions. +Verifying webhook requests ensures that incoming payloads originate from NexaFile and have not been tampered with. Without verification, attackers could forge requests to your endpoint and trigger unintended actions. -## How NexaSign Signs Webhooks +## How NexaFile Signs Webhooks -When you configure a webhook with a secret, NexaSign includes that secret in every webhook request via the `X-NexaSign-Secret` header. Your server should compare this header value against your stored secret to authenticate the request. +When you configure a webhook with a secret, NexaFile includes that secret in every webhook request via the `X-NexaSign-Secret` header. Your server should compare this header value against your stored secret to authenticate the request. ```bash POST /your-webhook-endpoint HTTP/1.1 @@ -197,8 +197,8 @@ app.post('/webhooks/nexasign', (req, res) => { | Issue | Cause | Solution | | --------------- | --------------------------------------- | ------------------------------------------------------------------ | -| Secret mismatch | Webhook secret changed or misconfigured | Verify the secret in your environment matches the one in NexaSign | -| Empty header | Webhook created without a secret | Add a secret to the webhook configuration in NexaSign | +| Secret mismatch | Webhook secret changed or misconfigured | Verify the secret in your environment matches the one in NexaFile | +| Empty header | Webhook created without a secret | Add a secret to the webhook configuration in NexaFile | | Encoding issues | String encoding mismatch | Ensure both secrets use the same encoding (UTF-8) | ## Security Best Practices @@ -230,7 +230,7 @@ const WEBHOOK_SECRET = 'my-secret-key'; // Never do this 1. Generate a new secret 2. Update your server to accept both old and new secrets temporarily -3. Update the webhook configuration in NexaSign +3. Update the webhook configuration in NexaFile 4. Remove the old secret from your server diff --git a/apps/docs/content/docs/index.mdx b/apps/docs/content/docs/index.mdx index e222eca..4070f14 100644 --- a/apps/docs/content/docs/index.mdx +++ b/apps/docs/content/docs/index.mdx @@ -1,5 +1,5 @@ --- -title: NexaSign Dokumentation +title: NexaFile Dokumentation description: Learn how to send documents for signing, integrate with the API, or self-host your own instance. full: true --- @@ -49,7 +49,7 @@ import {

Self-Hosting Guide

- Deploy your own NexaSign instance with Docker oder Kubernetes. + Deploy your own NexaFile instance with Docker oder Kubernetes.

Deploy now →
@@ -144,7 +144,7 @@ import {

Join the Community

- NexaSign is open source. Contribute, ask questions, or share feedback. + NexaFile is open source. Contribute, ask questions, or share feedback.

diff --git a/apps/docs/content/docs/policies/community-edition.mdx b/apps/docs/content/docs/policies/community-edition.mdx index f246500..31a9fcd 100644 --- a/apps/docs/content/docs/policies/community-edition.mdx +++ b/apps/docs/content/docs/policies/community-edition.mdx @@ -1,6 +1,6 @@ --- title: Community Edition -description: The open-source version of NexaSign, available under the AGPL-3.0 license. Includes core document signing functionality and can be self-hosted. +description: The open-source version of NexaFile, available under the AGPL-3.0 license. Includes core document signing functionality and can be self-hosted. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -24,7 +24,7 @@ Under the AGPL-3.0 license, you are permitted to: | Action | Description | | ------------------ | ------------------------------------------------------------- | -| **Use** | Run NexaSign for any purpose, including commercial use | +| **Use** | Run NexaFile for any purpose, including commercial use | | **Study** | Access and examine the complete source code | | **Modify** | Make changes and customizations to the software | | **Distribute** | Share copies of the original or modified software | @@ -37,7 +37,7 @@ When using or distributing the Community Edition, you must comply with these req - If you modify NexaSign and make it available over a network, you must: + If you modify NexaFile and make it available over a network, you must: - Provide access to the complete source code of your modified version - Make the source available through the same network interface, or provide a written offer to supply it @@ -45,7 +45,7 @@ When using or distributing the Community Edition, you must comply with these req The network clause is the distinguishing feature of AGPL-3.0. If users interact with your modified - NexaSign instance over a network (whether internal or external), you must provide them access to + NexaFile instance over a network (whether internal or external), you must provide them access to the source code. @@ -64,7 +64,7 @@ When using or distributing the Community Edition, you must comply with these req - Forks must use the same license - Modifications cannot be made proprietary - - Combined works that incorporate NexaSign code are subject to AGPL-3.0 + - Combined works that incorporate NexaFile code are subject to AGPL-3.0 @@ -74,7 +74,7 @@ When using or distributing the Community Edition, you must comply with these req ## Features Included -The Community Edition includes the core NexaSign functionality: +The Community Edition includes the core NexaFile functionality: @@ -127,7 +127,7 @@ Community Edition users have access to community-based support: - The NexaSign Discord server is the primary community support channel. You can: + The NexaFile Discord server is the primary community support channel. You can: - Ask questions and get help from other users - Share your use cases and solutions @@ -146,17 +146,17 @@ Community Edition users have access to community-based support: - Community support is provided on a best-effort basis by volunteers and NexaSign team members. For + Community support is provided on a best-effort basis by volunteers and NexaFile team members. For guaranteed response times and dedicated support, consider the Enterprise Edition. ## Contributing Back -Contributions to NexaSign are welcome and appreciated. You can contribute in several ways: +Contributions to NexaFile are welcome and appreciated. You can contribute in several ways: - 1. Fork the [NexaSign repository](https://github.com/NexaStack-Software/NexaSign) + 1. Fork the [NexaFile repository](https://github.com/NexaStack-Software/NexaSign) 2. Create a branch for your changes 3. Submit a pull request with a clear description 4. Respond to code review feedback diff --git a/apps/docs/content/docs/policies/enterprise-edition.mdx b/apps/docs/content/docs/policies/enterprise-edition.mdx index 940c63b..9f3db2b 100644 --- a/apps/docs/content/docs/policies/enterprise-edition.mdx +++ b/apps/docs/content/docs/policies/enterprise-edition.mdx @@ -1,6 +1,6 @@ --- title: Enterprise Edition -description: Commercial license that removes AGPL-3.0 source code disclosure requirements, allowing organisations to integrate NexaSign into proprietary products. +description: Commercial license that removes AGPL-3.0 source code disclosure requirements, allowing organisations to integrate NexaFile into proprietary products. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -12,13 +12,13 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; The Enterprise Edition is required when you: -- **Build proprietary products**: Integrate NexaSign into commercial software without releasing source code +- **Build proprietary products**: Integrate NexaFile into commercial software without releasing source code - **Offer SaaS with modifications**: Provide document signing as part of your platform with custom modifications you want to keep private - **Cannot comply with AGPL-3.0**: Corporate policies or legal requirements prohibit use of AGPL-licensed software -- **Need to keep modifications private**: Any changes to NexaSign source code that you don't want to disclose +- **Need to keep modifications private**: Any changes to NexaFile source code that you don't want to disclose - If you run NexaSign without modifications, or your modifications are open source under AGPL-3.0, + If you run NexaFile without modifications, or your modifications are open source under AGPL-3.0, the Community Edition is sufficient. @@ -28,8 +28,8 @@ The Enterprise Edition is required when you: | -------------------------------------------- | ------------------ | | Internal use without modifications | Community Edition | | Internal use with private modifications | Enterprise Edition | -| SaaS product using NexaSign API only | Community Edition | -| SaaS product with modified NexaSign code | Enterprise Edition | +| SaaS product using NexaFile API only | Community Edition | +| SaaS product with modified NexaFile code | Enterprise Edition | | White-label product with proprietary changes | Enterprise Edition | | Open-source project under AGPL-3.0 | Community Edition | @@ -40,8 +40,8 @@ The Enterprise Edition is required when you: The Enterprise license grants: - **No source disclosure**: Keep your modifications private. No obligation to share code with users or the public. - - **Proprietary integration**: Embed NexaSign in closed-source products without licensing conflicts. - - **Sublicensing options**: Distribute NexaSign as part of your product to your customers (terms vary by agreement). + - **Proprietary integration**: Embed NexaFile in closed-source products without licensing conflicts. + - **Sublicensing options**: Distribute NexaFile as part of your product to your customers (terms vary by agreement). - **Perpetual use**: License terms that allow continued use of the licensed version. @@ -73,7 +73,7 @@ The Enterprise Edition is required when you: NEXT_PRIVATE_NEXASIGN_LICENSE_KEY="your-license-key-here" ``` - 4. Restart your NexaSign instance + 4. Restart your NexaFile instance 5. Verify the license is active in the **Admin Panel** under the **Stats** section @@ -83,22 +83,22 @@ The Enterprise Edition is required when you: - The Enterprise license is a commercial agreement between your organisation and NexaSign. Key terms include: + The Enterprise license is a commercial agreement between your organisation and NexaFile. Key terms include: - - **Scope**: License to use, modify, and distribute NexaSign as specified in your agreement - - **Exclusions**: The license does not grant rights to NexaSign trademarks beyond what's specified + - **Scope**: License to use, modify, and distribute NexaFile as specified in your agreement + - **Exclusions**: The license does not grant rights to NexaFile trademarks beyond what's specified - **Termination**: License remains valid as long as subscription is active and terms are followed - - NexaSign application code + - NexaFile application code - Self-hosted deployments - Modifications and derivative works - Internal and external distribution (per agreement terms) - Third-party dependencies (these retain their original licenses) - - NexaSign Cloud service (separate subscription) + - NexaFile Cloud service (separate subscription) - Professional services (available separately) @@ -109,7 +109,7 @@ Enterprise pricing is based on: | Factor | Description | | ------------------- | ----------------------------------- | -| **Deployment type** | Self-hosted or NexaSign Cloud | +| **Deployment type** | Self-hosted or NexaFile Cloud | | **User count** | Number of users sending documents | | **Volume** | Monthly document signing volume | | **Support level** | Standard or premium support options | @@ -182,7 +182,7 @@ See [Support](/docs/policies/support) for complete support options. ### Evaluation - Options for evaluating NexaSign before purchase: + Options for evaluating NexaFile before purchase: - Test with the Community Edition (same codebase, AGPL-3.0 license) - Request an evaluation license for Enterprise features @@ -196,7 +196,7 @@ See [Support](/docs/policies/support) for complete support options. 1. Sign the Enterprise license agreement 2. Receive license key and access credentials - 3. Deploy using [self-hosting guides](/docs/self-hosting) or access NexaSign Cloud + 3. Deploy using [self-hosting guides](/docs/self-hosting) or access NexaFile Cloud 4. Configure Enterprise features with support assistance @@ -217,7 +217,7 @@ See [Support](/docs/policies/support) for complete support options. Yes. Your existing deployment can transition to the Enterprise license. Contact [sales](https://nexastack.co) to discuss migration. - + The license and cloud service are separate. Enterprise cloud plans include both the commercial license and hosted service. Self-hosted Enterprise licenses cover only the license rights. diff --git a/apps/docs/content/docs/policies/fair-use.mdx b/apps/docs/content/docs/policies/fair-use.mdx index e1137fb..4b03127 100644 --- a/apps/docs/content/docs/policies/fair-use.mdx +++ b/apps/docs/content/docs/policies/fair-use.mdx @@ -1,6 +1,6 @@ --- title: Fair Use Policy -description: Fair use guidelines for NexaSign Cloud to keep things sustainable for everyone. +description: Fair use guidelines for NexaFile Cloud to keep things sustainable for everyone. --- import { Callout } from 'fumadocs-ui/components/callout'; diff --git a/apps/docs/content/docs/policies/index.mdx b/apps/docs/content/docs/policies/index.mdx index f33426f..a97e6f5 100644 --- a/apps/docs/content/docs/policies/index.mdx +++ b/apps/docs/content/docs/policies/index.mdx @@ -11,12 +11,12 @@ description: License, privacy, terms, and support information /> The "network clause" is the distinguishing feature of AGPL-3.0. Unlike GPL-3.0, AGPL-3.0 treats - network access as distribution. If users interact with your modified NexaSign instance over a + network access as distribution. If users interact with your modified NexaFile instance over a network, you must provide them access to the source code. @@ -54,7 +54,7 @@ The Community Edition is appropriate when you: - Are building an open-source project - Can comply with AGPL-3.0 requirements -- Use NexaSign internally without modifications +- Use NexaFile internally without modifications - Want to contribute to the open-source ecosystem - Do not need to keep modifications proprietary @@ -65,13 +65,13 @@ See [Community Edition](/docs/policies/community-edition) for complete details. ## Enterprise Edition (Commercial License) -The Enterprise Edition provides a commercial license that removes the AGPL-3.0 requirements. This allows organisations to use, modify, and integrate NexaSign without source code disclosure obligations. +The Enterprise Edition provides a commercial license that removes the AGPL-3.0 requirements. This allows organisations to use, modify, and integrate NexaFile without source code disclosure obligations. ### What the Enterprise License Provides **No Source Code Disclosure**: Keep your modifications private. You are not required to share changes with users or the public. -**Proprietary Integration**: Integrate NexaSign into proprietary products and services without licensing conflicts. +**Proprietary Integration**: Integrate NexaFile into proprietary products and services without licensing conflicts. **Commercial Support**: Access to dedicated support channels and SLAs. @@ -81,14 +81,14 @@ The Enterprise Edition provides a commercial license that removes the AGPL-3.0 r The Enterprise Edition is appropriate when you: -- Build commercial products that incorporate NexaSign +- Build commercial products that incorporate NexaFile - Offer document signing as part of a SaaS platform - Cannot or prefer not to open-source your modifications - Need to comply with corporate policies that prohibit AGPL software - Require dedicated support and SLAs - If you modify NexaSign and provide network access to users (internal or external) without + If you modify NexaFile and provide network access to users (internal or external) without complying with AGPL-3.0 source disclosure requirements, you need an Enterprise license. @@ -102,8 +102,8 @@ See [Enterprise Edition](/docs/policies/enterprise-edition) for complete details Use this decision tree to determine which license fits your needs: - - **No modifications**: Both licenses work. Community Edition is free and sufficient if you run NexaSign as-is. + + **No modifications**: Both licenses work. Community Edition is free and sufficient if you run NexaFile as-is. **Yes, with modifications**: Continue to the next question. @@ -114,14 +114,14 @@ Use this decision tree to determine which license fits your needs: **No, modifications are proprietary**: Enterprise Edition is required. - + **Open-source product under AGPL-3.0**: Community Edition is appropriate. **Proprietary product**: Enterprise Edition is required. - Using NexaSign internally without providing network access to external users does not trigger AGPL-3.0 distribution requirements. However, if your organisation has policies against AGPL software or you make modifications you want to keep private, consider the Enterprise Edition. + Using NexaFile internally without providing network access to external users does not trigger AGPL-3.0 distribution requirements. However, if your organisation has policies against AGPL software or you make modifications you want to keep private, consider the Enterprise Edition. @@ -132,17 +132,17 @@ Use this decision tree to determine which license fits your needs: Yes. AGPL-3.0 permits commercial use. You must comply with the license terms, including source code disclosure if you modify and distribute or provide network access. - - No. Calling the NexaSign API from your application does not create a derivative work. Your - application remains under your chosen license. However, if you modify NexaSign itself and + + No. Calling the NexaFile API from your application does not create a derivative work. Your + application remains under your chosen license. However, if you modify NexaFile itself and provide network access, AGPL-3.0 requirements apply. - Modifying the source code, forking the repository and making changes, or linking NexaSign + Modifying the source code, forking the repository and making changes, or linking NexaFile libraries into your application in a way that creates a combined work. Configuration changes and - using NexaSign through its API are not modifications. + using NexaFile through its API are not modifications. - + You can change branding for your deployment under both licenses. Under AGPL-3.0, you must retain copyright notices and license information in the source code. Under the Enterprise license, you have more flexibility with branding requirements. @@ -155,8 +155,8 @@ Use this decision tree to determine which license fits your needs: Your existing deployments can transition to the Enterprise license. Contact [sales](https://nexastack.co) to discuss migration. - - Contributions to the main NexaSign repository are licensed under AGPL-3.0. The Enterprise + + Contributions to the main NexaFile repository are licensed under AGPL-3.0. The Enterprise license applies only to your private use and modifications. diff --git a/apps/docs/content/docs/policies/privacy.mdx b/apps/docs/content/docs/policies/privacy.mdx index dc15113..fe929a7 100644 --- a/apps/docs/content/docs/policies/privacy.mdx +++ b/apps/docs/content/docs/policies/privacy.mdx @@ -1,6 +1,6 @@ --- title: Privacy Policy -description: How NexaSign collects, uses, and protects your data. +description: How NexaFile collects, uses, and protects your data. --- Our full Privacy Policy is available at [nexastack.co](https://nexastack.co). diff --git a/apps/docs/content/docs/policies/security.mdx b/apps/docs/content/docs/policies/security.mdx index d8ee674..6d11649 100644 --- a/apps/docs/content/docs/policies/security.mdx +++ b/apps/docs/content/docs/policies/security.mdx @@ -1,6 +1,6 @@ --- title: Security -description: Security practices for NexaSign Cloud and self-hosted deployments, along with our vulnerability disclosure process. +description: Security practices for NexaFile Cloud and self-hosted deployments, along with our vulnerability disclosure process. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -27,7 +27,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Infrastructure Security -### NexaSign Cloud +### NexaFile Cloud The hosted cloud service uses the following security measures: @@ -48,7 +48,7 @@ Self-hosted deployments are responsible for their own infrastructure security. S - All data transmitted to and from NexaSign is encrypted using TLS 1.2 or higher. This includes: + All data transmitted to and from NexaFile is encrypted using TLS 1.2 or higher. This includes: - Web application traffic - API requests @@ -57,7 +57,7 @@ Self-hosted deployments are responsible for their own infrastructure security. S - For NexaSign Cloud: + For NexaFile Cloud: - Database contents are encrypted at rest - Document storage uses encrypted object storage @@ -67,7 +67,7 @@ Self-hosted deployments are responsible for their own infrastructure security. S - NexaSign encrypts sensitive data at the application level: + NexaFile encrypts sensitive data at the application level: - Encryption keys are configured via `NEXT_PRIVATE_ENCRYPTION_KEY` and `NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY` - Session tokens are signed using `NEXTAUTH_SECRET` @@ -103,7 +103,7 @@ Self-hosted deployments are responsible for their own infrastructure security. S ## Vulnerability Disclosure -NexaSign operates a responsible disclosure process for security vulnerabilities. +NexaFile operates a responsible disclosure process for security vulnerabilities. @@ -133,7 +133,7 @@ NexaSign operates a responsible disclosure process for security vulnerabilities. The following are in scope for vulnerability reports: -- NexaSign application code +- NexaFile application code - Authentication and authorization flaws - Data exposure vulnerabilities - Injection vulnerabilities @@ -192,7 +192,7 @@ See [Upgrades](/docs/self-hosting/maintenance/upgrades) for update procedures. ## Self-Hosted Security Considerations -When self-hosting NexaSign, you are responsible for the security of your deployment. The following recommendations apply: +When self-hosting NexaFile, you are responsible for the security of your deployment. The following recommendations apply: diff --git a/apps/docs/content/docs/policies/support.mdx b/apps/docs/content/docs/policies/support.mdx index 7c9b28c..6a7eccc 100644 --- a/apps/docs/content/docs/policies/support.mdx +++ b/apps/docs/content/docs/policies/support.mdx @@ -22,11 +22,11 @@ Community support is available to all users, including those on free plans and s -Join the NexaSign Discord server to: +Join the NexaFile Discord server to: - Ask questions and get help from the community - Share feedback and feature requests -- Connect with other NexaSign users +- Connect with other NexaFile users - Stay updated on announcements Discord is best for general questions and discussions. Response times vary based on community availability. @@ -41,7 +41,7 @@ Use GitHub for technical discussions and bug reports: When opening an issue, include: -1. NexaSign version +1. NexaFile version 2. Deployment method (Cloud, self-hosted Docker, Kubernetes, etc.) 3. Steps to reproduce the problem 4. Expected vs actual behavior @@ -57,7 +57,7 @@ When opening an issue, include: ## Paid Support Tiers -Paid plans include access to direct support from the NexaSign team. +Paid plans include access to direct support from the NexaFile team. @@ -66,7 +66,7 @@ Available on paid subscription plans: - Email support at info@nexastack.co - Account and billing assistance -- Technical guidance for NexaSign Cloud usage +- Technical guidance for NexaFile Cloud usage - Response during business hours @@ -75,7 +75,7 @@ Available on paid subscription plans: Available on [Platform plans](https://nexastack.co) and above: - All standard support channels -- Private Discord channel for direct communication with the NexaSign team +- Private Discord channel for direct communication with the NexaFile team - Private Slack workspace for closer collaboration @@ -129,7 +129,7 @@ Response times are targets, not guarantees. Actual times may vary based on issue -- Guidance on NexaSign features and functionality +- Guidance on NexaFile features and functionality - Help with configuration and settings - Troubleshooting application errors - Account and billing questions (paid plans) @@ -219,7 +219,7 @@ Do not report security vulnerabilities through public channels (GitHub Issues, D -NexaSign follows responsible disclosure practices. Security researchers who report valid vulnerabilities responsibly will be acknowledged. +NexaFile follows responsible disclosure practices. Security researchers who report valid vulnerabilities responsibly will be acknowledged. ## Contact @@ -237,4 +237,4 @@ NexaSign follows responsible disclosure practices. Security researchers who repo - [Troubleshooting](/docs/self-hosting/maintenance/troubleshooting) - Self-hosted issue resolution - [Self-Hosting](/docs/self-hosting) - Deployment and configuration guides - [Enterprise Edition](/docs/policies/enterprise-edition) - Commercial licensing options -- [Privacy Policy](/docs/policies/privacy) - How NexaSign handles your data +- [Privacy Policy](/docs/policies/privacy) - How NexaFile handles your data diff --git a/apps/docs/content/docs/policies/terms.mdx b/apps/docs/content/docs/policies/terms.mdx index bca02d1..ace9f9d 100644 --- a/apps/docs/content/docs/policies/terms.mdx +++ b/apps/docs/content/docs/policies/terms.mdx @@ -1,6 +1,6 @@ --- title: Terms of Service -description: The terms that govern your use of NexaSign. +description: The terms that govern your use of NexaFile. --- Our full Terms of Service are available at [nexastack.co](https://nexastack.co). diff --git a/apps/docs/content/docs/self-hosting/configuration/advanced/ai-features.mdx b/apps/docs/content/docs/self-hosting/configuration/advanced/ai-features.mdx index 96e8e30..c959208 100644 --- a/apps/docs/content/docs/self-hosting/configuration/advanced/ai-features.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/advanced/ai-features.mdx @@ -1,6 +1,6 @@ --- title: AI Recipient & Field Detection (Self-hosting) -description: Configure Google Vertex AI so NexaSign can detect recipients and fields automatically. +description: Configure Google Vertex AI so NexaFile can detect recipients and fields automatically. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -9,7 +9,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Overview -This guide covers how to enable the AI recipient and field detection features when you self-host NexaSign. +This guide covers how to enable the AI recipient and field detection features when you self-host NexaFile. ## What This Enables @@ -21,7 +21,7 @@ This guide covers how to enable the AI recipient and field detection features wh - A Google Cloud project with the **Vertex AI API** enabled and billing active. - A **Vertex AI Express API key** with access to Gemini models (create via the [Vertex AI Express flow](https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode/overview) and manage keys in [API keys](https://cloud.google.com/vertex-ai/generative-ai/docs/start/api-keys)). -- NexaSign version that includes the AI detection feature and the corresponding database migration. +- NexaFile version that includes the AI detection feature and the corresponding database migration. ## Configure Environment Variables @@ -36,17 +36,17 @@ GOOGLE_VERTEX_LOCATION="global" Use a region close to your users if you need data residency considerations (e.g. `europe-west1`). - If you omit the location, NexaSign uses `global`. Not all models are available in every region; + If you omit the location, NexaFile uses `global`. Not all models are available in every region; if a model is unavailable, switch to a supported region. ## Deploy with the Published Container -- Use the official NexaSign image (DockerHub or GHCR) and supply the Vertex env vars above. +- Use the official NexaFile image (DockerHub or GHCR) and supply the Vertex env vars above. - Ensure migrations run on startup (the container runs `prisma migrate deploy` in production mode). - Restart the container after adding or changing Vertex env vars. -## Enable the Feature in NexaSign +## Enable the Feature in NexaFile Once the service is running with the Vertex env vars: diff --git a/apps/docs/content/docs/self-hosting/configuration/advanced/oauth-providers.mdx b/apps/docs/content/docs/self-hosting/configuration/advanced/oauth-providers.mdx index c776750..e05b720 100644 --- a/apps/docs/content/docs/self-hosting/configuration/advanced/oauth-providers.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/advanced/oauth-providers.mdx @@ -1,6 +1,6 @@ --- title: Setting up OAuth Providers -description: Learn how to set up OAuth providers for your own instance of NexaSign. +description: Learn how to set up OAuth providers for your own instance of NexaFile. --- import { Step, Steps } from 'fumadocs-ui/components/steps'; @@ -55,7 +55,7 @@ Set: ### Set environment variables -In your NexaSign environment, set: +In your NexaFile environment, set: ``` NEXT_PRIVATE_GOOGLE_CLIENT_ID= @@ -90,7 +90,7 @@ In the left sidebar, click **App registrations**, then **New registration**. ### Name and choose account types -Enter a name (e.g. "NexaSign"). +Enter a name (e.g. "NexaFile"). Under **Supported account types**, select both: @@ -136,7 +136,7 @@ After registration you're on the app overview page. Copy the **Application (clie ### Set environment variables -In your NexaSign environment, set: +In your NexaFile environment, set: ``` NEXT_PRIVATE_MICROSOFT_CLIENT_ID= diff --git a/apps/docs/content/docs/self-hosting/configuration/background-jobs.mdx b/apps/docs/content/docs/self-hosting/configuration/background-jobs.mdx index c122428..9874fa1 100644 --- a/apps/docs/content/docs/self-hosting/configuration/background-jobs.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/background-jobs.mdx @@ -1,6 +1,6 @@ --- title: Background Jobs -description: Configure how NexaSign processes background tasks like email delivery, document processing, and webhook dispatch. +description: Configure how NexaFile processes background tasks like email delivery, document processing, and webhook dispatch. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -8,7 +8,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Overview -NexaSign processes background jobs for email delivery, document sealing, webhook dispatch, and scheduled maintenance tasks. Three providers are available: +NexaFile processes background jobs for email delivery, document sealing, webhook dispatch, and scheduled maintenance tasks. Three providers are available: | Provider | Backend | Best For | Infrastructure | | -------- | ---------- | ----------------------------------------------- | -------------- | @@ -66,7 +66,7 @@ INNGEST_SIGNING_KEY=your-signing-key ## BullMQ -[BullMQ](https://docs.bullmq.io/) is a Redis-backed job queue that runs inside the NexaSign process. It provides higher throughput than the local provider, configurable concurrency, and a built-in dashboard for monitoring jobs. +[BullMQ](https://docs.bullmq.io/) is a Redis-backed job queue that runs inside the NexaFile process. It provides higher throughput than the local provider, configurable concurrency, and a built-in dashboard for monitoring jobs. ### Requirements @@ -110,7 +110,7 @@ volumes: redis_data: ``` -Then set `NEXT_PRIVATE_REDIS_URL=redis://redis:6379` in your NexaSign environment. +Then set `NEXT_PRIVATE_REDIS_URL=redis://redis:6379` in your NexaFile environment. ### Advantages @@ -124,7 +124,7 @@ Then set `NEXT_PRIVATE_REDIS_URL=redis://redis:6379` in your NexaSign environmen ## Local -The local provider uses your PostgreSQL database as a job queue. Jobs are stored in the `BackgroundJob` table and processed via internal HTTP requests that NexaSign sends to itself. +The local provider uses your PostgreSQL database as a job queue. Jobs are stored in the `BackgroundJob` table and processed via internal HTTP requests that NexaFile sends to itself. ### Setup @@ -137,7 +137,7 @@ NEXT_PRIVATE_JOBS_PROVIDER=local ### Internal URL -Background jobs in the local provider work by NexaSign sending HTTP requests to itself. If your reverse proxy or network setup causes issues with the app reaching its own public URL, set the internal URL: +Background jobs in the local provider work by NexaFile sending HTTP requests to itself. If your reverse proxy or network setup causes issues with the app reaching its own public URL, set the internal URL: ```bash NEXT_PRIVATE_INTERNAL_WEBAPP_URL=http://localhost:3000 diff --git a/apps/docs/content/docs/self-hosting/configuration/database.mdx b/apps/docs/content/docs/self-hosting/configuration/database.mdx index bfdf647..e1e13af 100644 --- a/apps/docs/content/docs/self-hosting/configuration/database.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/database.mdx @@ -1,6 +1,6 @@ --- title: Database Configuration -description: Configure PostgreSQL connection strings, pooling, SSL, migrations, and performance tuning for your NexaSign deployment. +description: Configure PostgreSQL connection strings, pooling, SSL, migrations, and performance tuning for your NexaFile deployment. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -9,7 +9,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Supported Databases -NexaSign requires **PostgreSQL 14 or later**. No other databases are supported. +NexaFile requires **PostgreSQL 14 or later**. No other databases are supported. PostgreSQL provides the reliability, performance, and feature set required for document signing workflows, including: @@ -61,7 +61,7 @@ postgresql://nexasign:p%40ss%23word@localhost:5432/nexasign ## Environment Variables -NexaSign uses two database connection variables: +NexaFile uses two database connection variables: | Variable | Purpose | | ---------------------------------- | --------------------------------------------------- | @@ -79,7 +79,7 @@ NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://user:password@host:5432/nexasign ### Automatic Detection -NexaSign automatically detects common database environment variable formats used by hosting providers: +NexaFile automatically detects common database environment variable formats used by hosting providers: | Provider Variable | Maps To | | -------------------------- | ---------------------------------- | @@ -89,7 +89,7 @@ NexaSign automatically detects common database environment variable formats used | `DATABASE_URL_UNPOOLED` | `NEXT_PRIVATE_DIRECT_DATABASE_URL` | | `POSTGRES_URL_NON_POOLING` | `NEXT_PRIVATE_DIRECT_DATABASE_URL` | -If your hosting provider sets these variables, NexaSign will use them automatically. +If your hosting provider sets these variables, NexaFile will use them automatically. ## Connection Pooling @@ -125,7 +125,7 @@ NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://user:password@db-host:5432/nexasig ### Prisma Connection Pool -NexaSign uses Prisma, which maintains its own connection pool. Configure pool size with connection string parameters: +NexaFile uses Prisma, which maintains its own connection pool. Configure pool size with connection string parameters: ``` postgresql://user:password@host:5432/nexasign?connection_limit=10&pool_timeout=30 @@ -178,11 +178,11 @@ docker run -d \ ## Running Migrations -Database migrations update your schema when upgrading NexaSign. +Database migrations update your schema when upgrading NexaFile. ### Automatic Migrations -When running NexaSign via Docker, migrations run automatically on container startup. No manual intervention is required. +When running NexaFile via Docker, migrations run automatically on container startup. No manual intervention is required. ### Manual Migrations @@ -369,7 +369,7 @@ Most managed database services provide automated backups: ### PostgreSQL Configuration -Key parameters for NexaSign workloads: +Key parameters for NexaFile workloads: | Parameter | Recommended Value | Description | | ---------------------- | ----------------- | ------------------------------------- | @@ -391,7 +391,7 @@ Example: 3 app instances with pool size 10 = `(3 × 10) + 10 = 40` connections m ### Indexing -NexaSign includes necessary indexes by default. Additional indexes may help for: +NexaFile includes necessary indexes by default. Additional indexes may help for: - Custom reporting queries - High-volume document searches diff --git a/apps/docs/content/docs/self-hosting/configuration/email.mdx b/apps/docs/content/docs/self-hosting/configuration/email.mdx index e4d9a64..4b7139e 100644 --- a/apps/docs/content/docs/self-hosting/configuration/email.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/email.mdx @@ -9,7 +9,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Supported Email Transports -NexaSign supports four email transport methods: +NexaFile supports four email transport methods: | Transport | Use Case | Configuration Complexity | | -------------- | ------------------------------------- | ------------------------ | @@ -31,7 +31,7 @@ All transports require sender configuration: ```bash NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@example.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` @@ -41,7 +41,7 @@ NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" ## SMTP Configuration -SMTP is the most common email transport. NexaSign supports two SMTP authentication methods. +SMTP is the most common email transport. NexaFile supports two SMTP authentication methods. ### SMTP with Username/Password (smtp-auth) @@ -69,7 +69,7 @@ NEXT_PRIVATE_SMTP_PORT="587" NEXT_PRIVATE_SMTP_USERNAME="your-username" NEXT_PRIVATE_SMTP_PASSWORD="your-password" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@example.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` ### Common SMTP Provider Examples @@ -83,7 +83,7 @@ NEXT_PRIVATE_SMTP_PORT="587" NEXT_PRIVATE_SMTP_USERNAME="your-email@gmail.com" NEXT_PRIVATE_SMTP_PASSWORD="your-app-password" NEXT_PRIVATE_SMTP_FROM_ADDRESS="your-email@gmail.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` @@ -100,7 +100,7 @@ NEXT_PRIVATE_SMTP_PORT="587" NEXT_PRIVATE_SMTP_USERNAME="your-email@yourdomain.com" NEXT_PRIVATE_SMTP_PASSWORD="your-password" NEXT_PRIVATE_SMTP_FROM_ADDRESS="your-email@yourdomain.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` **Amazon SES:** @@ -112,7 +112,7 @@ NEXT_PRIVATE_SMTP_PORT="587" NEXT_PRIVATE_SMTP_USERNAME="your-ses-smtp-username" NEXT_PRIVATE_SMTP_PASSWORD="your-ses-smtp-password" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@yourdomain.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` **Postmark:** @@ -124,7 +124,7 @@ NEXT_PRIVATE_SMTP_PORT="587" NEXT_PRIVATE_SMTP_USERNAME="your-postmark-server-api-token" NEXT_PRIVATE_SMTP_PASSWORD="your-postmark-server-api-token" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@yourdomain.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` ### SMTP with API Key (smtp-api) @@ -151,7 +151,7 @@ NEXT_PRIVATE_SMTP_PORT="587" NEXT_PRIVATE_SMTP_APIKEY_USER="apikey" NEXT_PRIVATE_SMTP_APIKEY="SG.xxxxxxxxxxxxxxxxxxxx" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@yourdomain.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` ## Resend Configuration @@ -171,7 +171,7 @@ NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" NEXT_PRIVATE_SMTP_TRANSPORT="resend" NEXT_PRIVATE_RESEND_API_KEY="re_xxxxxxxxxxxxxxxxxxxx" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@yourdomain.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` **Setup Steps:** @@ -193,7 +193,7 @@ Configure your domain in the Resend dashboard so you can send from your own addr ### Create an API key -Generate an API key in the Resend dashboard for NexaSign to use. +Generate an API key in the Resend dashboard for NexaFile to use. @@ -225,7 +225,7 @@ Set the variables in the table above, including `NEXT_PRIVATE_RESEND_API_KEY` an NEXT_PRIVATE_SMTP_TRANSPORT="mailchannels" NEXT_PRIVATE_MAILCHANNELS_API_KEY="your-api-key" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@yourdomain.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` **With DKIM Signing:** @@ -237,12 +237,12 @@ NEXT_PRIVATE_MAILCHANNELS_DKIM_DOMAIN="yourdomain.com" NEXT_PRIVATE_MAILCHANNELS_DKIM_SELECTOR="mailchannels" NEXT_PRIVATE_MAILCHANNELS_DKIM_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@yourdomain.com" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" ``` ## Email Templates -NexaSign uses React Email templates for all outgoing emails. The templates are located in `packages/email/templates/` and include: +NexaFile uses React Email templates for all outgoing emails. The templates are located in `packages/email/templates/` and include: | Template | Purpose | | ------------------------- | ----------------------------------------- | @@ -260,7 +260,7 @@ NexaSign uses React Email templates for all outgoing emails. The templates are l Email templates support branding customization through organisation settings. When branding is enabled: -- Custom logo replaces the NexaSign logo +- Custom logo replaces the NexaFile logo - Branding colors are applied to email elements Configure branding in the application under **Organisation Settings > Preferences > Branding**. @@ -285,14 +285,14 @@ For development or testing, use a local SMTP server like [Mailhog](https://githu docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog ``` -Configure NexaSign to use the test server: +Configure NexaFile to use the test server: ```bash NEXT_PRIVATE_SMTP_TRANSPORT="smtp-auth" NEXT_PRIVATE_SMTP_HOST="localhost" NEXT_PRIVATE_SMTP_PORT="1025" NEXT_PRIVATE_SMTP_FROM_ADDRESS="test@localhost" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign Test" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile Test" ``` View sent emails at `http://localhost:8025`. @@ -356,7 +356,7 @@ Enable DKIM signing in your provider settings. -For MailChannels, configure DKIM directly in NexaSign using the environment variables described above. +For MailChannels, configure DKIM directly in NexaFile using the environment variables described above. ### DMARC Configuration diff --git a/apps/docs/content/docs/self-hosting/configuration/environment.mdx b/apps/docs/content/docs/self-hosting/configuration/environment.mdx index f4935cb..66004ff 100644 --- a/apps/docs/content/docs/self-hosting/configuration/environment.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/environment.mdx @@ -1,18 +1,18 @@ --- title: Environment Variables -description: Complete reference for all environment variables used to configure a self-hosted NexaSign instance. +description: Complete reference for all environment variables used to configure a self-hosted NexaFile instance. --- ## Required Variables -These variables must be set for NexaSign to function: +These variables must be set for NexaFile to function: | Variable | Description | | --------------------------------------- | ------------------------------------------------------------------------------------------ | | `NEXTAUTH_SECRET` | Secret key for NextAuth.js encryption and signing. Generate with `openssl rand -base64 32` | | `NEXT_PRIVATE_ENCRYPTION_KEY` | Primary encryption key for symmetric encryption (minimum 32 characters) | | `NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY` | Secondary encryption key for symmetric encryption (minimum 32 characters) | -| `NEXT_PUBLIC_WEBAPP_URL` | Public URL of your NexaSign instance (e.g., `https://sign.example.com`) | +| `NEXT_PUBLIC_WEBAPP_URL` | Public URL of your NexaFile instance (e.g., `https://sign.example.com`) | | `NEXT_PRIVATE_DATABASE_URL` | PostgreSQL connection URL with connection pooling | | `NEXT_PRIVATE_SMTP_FROM_ADDRESS` | Email address used as the sender for all outgoing emails | | `NEXT_PRIVATE_SMTP_FROM_NAME` | Display name for the sender of outgoing emails | @@ -30,7 +30,7 @@ These variables must be set for NexaSign to function: ## Database Configuration -NexaSign requires PostgreSQL 14 or higher. +NexaFile requires PostgreSQL 14 or higher. | Variable | Required | Description | | ---------------------------------- | ------------ | ------------------------------------------------------------------------------------------ | @@ -90,7 +90,7 @@ Callback URL: `https:///api/auth/callback/microsoft` ## Email Configuration -NexaSign supports multiple email transports for sending notifications. +NexaFile supports multiple email transports for sending notifications. ### Transport Selection @@ -148,7 +148,7 @@ For detailed email setup, see [Email Configuration](/docs/self-hosting/configura ## Storage Configuration -NexaSign can store documents in the database or S3-compatible storage. +NexaFile can store documents in the database or S3-compatible storage. | Variable | Description | Default | | ---------------------------------------- | ------------------------------------------- | ---------- | @@ -182,7 +182,7 @@ For detailed storage setup, see [Storage Configuration](/docs/self-hosting/confi ## Signing Certificate Configuration -NexaSign requires a certificate to digitally sign documents. +NexaFile requires a certificate to digitally sign documents. ### Transport Selection @@ -254,7 +254,7 @@ NEXT_PUBLIC_DISABLE_SIGNUP="true" ## AI Features -NexaSign can use Google Vertex AI for recipient and field detection. +NexaFile can use Google Vertex AI for recipient and field detection. | Variable | Description | Default | | -------------------------- | ---------------------------------------------- | -------- | @@ -268,7 +268,7 @@ AI features must also be enabled in organisation/team settings after configurati ## Background Jobs -NexaSign supports multiple background job providers for processing emails, documents, webhooks, and scheduled tasks. +NexaFile supports multiple background job providers for processing emails, documents, webhooks, and scheduled tasks. ### Provider Selection @@ -363,7 +363,7 @@ NEXT_PRIVATE_SMTP_HOST="smtp.example.com" NEXT_PRIVATE_SMTP_PORT=587 NEXT_PRIVATE_SMTP_USERNAME="your-smtp-user" NEXT_PRIVATE_SMTP_PASSWORD="your-smtp-password" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@example.com" # Signing (certificate must be configured) diff --git a/apps/docs/content/docs/self-hosting/configuration/index.mdx b/apps/docs/content/docs/self-hosting/configuration/index.mdx index 395784a..b5d94bb 100644 --- a/apps/docs/content/docs/self-hosting/configuration/index.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/index.mdx @@ -1,6 +1,6 @@ --- title: Configuration -description: Configure your self-hosted NexaSign instance with environment variables, database, email, storage, and signing. +description: Configure your self-hosted NexaFile instance with environment variables, database, email, storage, and signing. --- diff --git a/apps/docs/content/docs/self-hosting/configuration/signing-certificate/google-cloud-hsm.mdx b/apps/docs/content/docs/self-hosting/configuration/signing-certificate/google-cloud-hsm.mdx index be46e19..84f6534 100644 --- a/apps/docs/content/docs/self-hosting/configuration/signing-certificate/google-cloud-hsm.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/signing-certificate/google-cloud-hsm.mdx @@ -27,13 +27,13 @@ Create an HSM key ring and an asymmetric signing key in Cloud KMS (see [Creating ### Create service account -Create a service account with the `cloudkms.signerVerifier` role so NexaSign can use the key. +Create a service account with the `cloudkms.signerVerifier` role so NexaFile can use the key. ### Export public certificate -Export the public certificate from the HSM key; NexaSign needs it to embed in signatures. +Export the public certificate from the HSM key; NexaFile needs it to embed in signatures. diff --git a/apps/docs/content/docs/self-hosting/configuration/signing-certificate/index.mdx b/apps/docs/content/docs/self-hosting/configuration/signing-certificate/index.mdx index 2085a88..658096b 100644 --- a/apps/docs/content/docs/self-hosting/configuration/signing-certificate/index.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/signing-certificate/index.mdx @@ -1,17 +1,17 @@ --- title: Signing Certificate -description: Configure the X.509 signing certificate used for digital signatures in self-hosted NexaSign. +description: Configure the X.509 signing certificate used for digital signatures in self-hosted NexaFile. --- import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; -When a document is completed in NexaSign, it is digitally signed using an X.509 certificate. This cryptographic signature provides: +When a document is completed in NexaFile, it is digitally signed using an X.509 certificate. This cryptographic signature provides: - Proof of document authenticity - Verification that the document has not been modified since signing - Identity information about the signing entity -Self-hosted NexaSign instances require a signing certificate. You can generate a self-signed certificate or purchase one from a Certificate Authority (CA). +Self-hosted NexaFile instances require a signing certificate. You can generate a self-signed certificate or purchase one from a Certificate Authority (CA). -For organisations requiring hardware-based key protection, NexaSign supports Google Cloud HSM. This provides: +For organisations requiring hardware-based key protection, NexaFile supports Google Cloud HSM. This provides: - FIPS 140-2 Level 3 certified key storage - Keys never leave the HSM diff --git a/apps/docs/content/docs/self-hosting/configuration/signing-certificate/troubleshooting.mdx b/apps/docs/content/docs/self-hosting/configuration/signing-certificate/troubleshooting.mdx index 79e575c..cd2e8c5 100644 --- a/apps/docs/content/docs/self-hosting/configuration/signing-certificate/troubleshooting.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/signing-certificate/troubleshooting.mdx @@ -53,7 +53,7 @@ import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; Solution: - Generate a new certificate or obtain a renewed one - - Update the certificate file and restart NexaSign + - Update the certificate file and restart NexaFile - Check expiration: ```bash diff --git a/apps/docs/content/docs/self-hosting/configuration/storage.mdx b/apps/docs/content/docs/self-hosting/configuration/storage.mdx index 53b75b2..b525f01 100644 --- a/apps/docs/content/docs/self-hosting/configuration/storage.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/storage.mdx @@ -57,7 +57,7 @@ No configuration required. Database storage is enabled when `NEXT_PUBLIC_UPLOAD_ ## S3 Configuration -S3 storage is recommended for production deployments. NexaSign supports AWS S3 and any S3-compatible storage service. +S3 storage is recommended for production deployments. NexaFile supports AWS S3 and any S3-compatible storage service. ### Required Variables @@ -175,7 +175,7 @@ docker run -d \ minio/minio server /data --console-address ":9001" ``` -Using Docker Compose with NexaSign: +Using Docker Compose with NexaFile: ```yaml services: @@ -235,7 +235,7 @@ NEXT_PRIVATE_UPLOAD_REGION=us-east-1 ## Other S3-Compatible Services -NexaSign works with any S3-compatible storage service. Configure the endpoint and enable path-style URLs if required. +NexaFile works with any S3-compatible storage service. Configure the endpoint and enable path-style URLs if required. ### Cloudflare R2 @@ -289,7 +289,7 @@ Use Amazon CloudFront to serve documents with lower latency and reduced S3 costs ### Prerequisites -- An S3 bucket configured for NexaSign +- An S3 bucket configured for NexaFile - A CloudFront distribution with the S3 bucket as origin - A CloudFront key pair for signing URLs @@ -377,7 +377,7 @@ Signed URLs expire after 1 hour. ## Migration Between Storage Backends -NexaSign does not provide automatic migration between storage backends. Each document's storage location is recorded in the database. +NexaFile does not provide automatic migration between storage backends. Each document's storage location is recorded in the database. Documents uploaded to one storage backend cannot be automatically migrated to another. Plan your @@ -418,7 +418,7 @@ This requires custom scripts and database modifications. ### Hybrid Operation -During migration, NexaSign can read from both backends. The `DocumentData.type` field indicates where each document is stored. +During migration, NexaFile can read from both backends. The `DocumentData.type` field indicates where each document is stored. - `BYTES_64`: Stored in database - `S3_PATH`: Stored in S3 diff --git a/apps/docs/content/docs/self-hosting/configuration/telemetry.mdx b/apps/docs/content/docs/self-hosting/configuration/telemetry.mdx index d87276d..0268640 100644 --- a/apps/docs/content/docs/self-hosting/configuration/telemetry.mdx +++ b/apps/docs/content/docs/self-hosting/configuration/telemetry.mdx @@ -1,6 +1,6 @@ --- title: Telemetry -description: Learn about the telemetry data that NexaSign collects from self-hosted instances. +description: Learn about the telemetry data that NexaFile collects from self-hosted instances. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -8,13 +8,13 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Overview -NexaSign collects anonymous telemetry data from self-hosted instances to help us understand how the software is being used and make improvements to the product. This telemetry is enabled by default, but you can easily disable it if you prefer. +NexaFile collects anonymous telemetry data from self-hosted instances to help us understand how the software is being used and make improvements to the product. This telemetry is enabled by default, but you can easily disable it if you prefer. ## What We Collect We collect minimal, privacy-preserving information that helps us understand the health and adoption of self-hosted installations: -- **App Version**: The version of NexaSign you are running. This helps us understand which versions are in use and prioritize support for older versions. +- **App Version**: The version of NexaFile you are running. This helps us understand which versions are in use and prioritize support for older versions. - **Installation ID**: A unique identifier for your installation. This is stored in your database and helps us count distinct installations without knowing who you are. diff --git a/apps/docs/content/docs/self-hosting/deployment/docker-compose.mdx b/apps/docs/content/docs/self-hosting/deployment/docker-compose.mdx index 7f126d7..684ac27 100644 --- a/apps/docs/content/docs/self-hosting/deployment/docker-compose.mdx +++ b/apps/docs/content/docs/self-hosting/deployment/docker-compose.mdx @@ -1,6 +1,6 @@ --- title: Docker Compose -description: Deploy NexaSign with Docker Compose, including PostgreSQL. This production-ready setup is suitable for most self-hosted deployments. +description: Deploy NexaFile with Docker Compose, including PostgreSQL. This production-ready setup is suitable for most self-hosted deployments. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -109,7 +109,7 @@ volumes: | `database` | PostgreSQL 15 database with persistent storage | | `nexasign` | Main application container, waits for database to be healthy | -The NexaSign container waits for the database health check to pass before starting. +The NexaFile container waits for the database health check to pass before starting. ## Environment Configuration @@ -128,7 +128,7 @@ NEXTAUTH_SECRET=your-nextauth-secret NEXT_PRIVATE_ENCRYPTION_KEY=your-encryption-key-min-32-characters NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=your-secondary-key-min-32-characters -# Public URL where NexaSign is accessible +# Public URL where NexaFile is accessible NEXT_PUBLIC_WEBAPP_URL=https://sign.example.com NEXT_PRIVATE_INTERNAL_WEBAPP_URL=http://localhost:3000 @@ -141,7 +141,7 @@ NEXT_PRIVATE_SMTP_HOST=smtp.example.com NEXT_PRIVATE_SMTP_PORT=587 NEXT_PRIVATE_SMTP_USERNAME=your-smtp-username NEXT_PRIVATE_SMTP_PASSWORD=your-smtp-password -NEXT_PRIVATE_SMTP_FROM_NAME=NexaSign +NEXT_PRIVATE_SMTP_FROM_NAME=NexaFile NEXT_PRIVATE_SMTP_FROM_ADDRESS=noreply@example.com ``` @@ -238,7 +238,7 @@ docker compose logs -f nexasign Look for "Ready" or "Listening on port 3000" in the output. -## Accessing NexaSign +## Accessing NexaFile Once the containers are running: @@ -311,7 +311,7 @@ docker compose down -v Using `down -v` deletes the database volume. Back up your data first. -### Update NexaSign +### Update NexaFile {/* prettier-ignore */} @@ -343,7 +343,7 @@ Database migrations run automatically on container startup. ### Reverse Proxy -For production, place NexaSign behind a reverse proxy for SSL termination: +For production, place NexaFile behind a reverse proxy for SSL termination: **nginx example:** diff --git a/apps/docs/content/docs/self-hosting/deployment/docker.mdx b/apps/docs/content/docs/self-hosting/deployment/docker.mdx index 84e4fc8..e6813a0 100644 --- a/apps/docs/content/docs/self-hosting/deployment/docker.mdx +++ b/apps/docs/content/docs/self-hosting/deployment/docker.mdx @@ -1,6 +1,6 @@ --- title: Docker -description: Run NexaSign as a standalone Docker container with an external database. Ideal for container platforms like AWS ECS, Google Cloud Run, or Azure Container Instances. +description: Run NexaFile as a standalone Docker container with an external database. Ideal for container platforms like AWS ECS, Google Cloud Run, or Azure Container Instances. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -46,14 +46,14 @@ docker pull NexaStack-Software/NexaSign:latest ### Required Variables -These variables must be set for NexaSign to start: +These variables must be set for NexaFile to start: | Variable | Description | Default | | --------------------------------------- | --------------------------------------------------------------------------- | ----------------------------- | | `NEXTAUTH_SECRET` | Secret key for session encryption. Generate with `openssl rand -base64 32` | - | | `NEXT_PRIVATE_ENCRYPTION_KEY` | Primary encryption key (minimum 32 characters) | - | | `NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY` | Secondary encryption key (minimum 32 characters) | - | -| `NEXT_PUBLIC_WEBAPP_URL` | Public URL where NexaSign is accessible (e.g., `https://sign.example.com`) | - | +| `NEXT_PUBLIC_WEBAPP_URL` | Public URL where NexaFile is accessible (e.g., `https://sign.example.com`) | - | | `NEXT_PRIVATE_INTERNAL_WEBAPP_URL` | Internal URL the app uses to call itself (for background jobs) | Same as `NEXT_PUBLIC_WEBAPP_URL` | | `NEXT_PRIVATE_DATABASE_URL` | PostgreSQL connection string | - | | `NEXT_PRIVATE_SMTP_TRANSPORT` | Email transport: `smtp-auth`, `smtp-api`, `resend`, or `mailchannels` | `smtp-auth` | @@ -62,7 +62,7 @@ These variables must be set for NexaSign to start: ### Database Connection -NexaSign requires two database connection strings: +NexaFile requires two database connection strings: | Variable | Required | Default | Description | | ---------------------------------- | ------------ | --------------------------- | --------------------------------- | @@ -126,7 +126,7 @@ docker run -d \ -e NEXT_PRIVATE_SMTP_PORT="587" \ -e NEXT_PRIVATE_SMTP_USERNAME="your-smtp-user" \ -e NEXT_PRIVATE_SMTP_PASSWORD="your-smtp-password" \ - -e NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" \ + -e NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" \ -e NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@example.com" \ NexaStack-Software/NexaSign:latest ``` @@ -168,7 +168,7 @@ NEXT_PRIVATE_SMTP_HOST=smtp.example.com NEXT_PRIVATE_SMTP_PORT=587 NEXT_PRIVATE_SMTP_USERNAME=your-smtp-user NEXT_PRIVATE_SMTP_PASSWORD=your-smtp-password -NEXT_PRIVATE_SMTP_FROM_NAME=NexaSign +NEXT_PRIVATE_SMTP_FROM_NAME=NexaFile NEXT_PRIVATE_SMTP_FROM_ADDRESS=noreply@example.com ``` @@ -185,7 +185,7 @@ docker run -d \ ## Health Checks -NexaSign provides health check endpoints for monitoring: +NexaFile provides health check endpoints for monitoring: | Endpoint | Purpose | | ------------------------- | -------------------------------------------------------------- | @@ -216,7 +216,7 @@ docker inspect --format='{{.State.Health.Status}}' nexasign ## Updating the Container -To update NexaSign to a new version: +To update NexaFile to a new version: {/* prettier-ignore */} @@ -262,7 +262,7 @@ docker run -d \ ## Persistence -The NexaSign container is stateless. All persistent data is stored in the PostgreSQL database. +The NexaFile container is stateless. All persistent data is stored in the PostgreSQL database. By default, documents are also stored in the database. For high-volume deployments, configure S3-compatible storage instead. See [Storage Configuration](/docs/self-hosting/configuration/storage) for S3 setup. diff --git a/apps/docs/content/docs/self-hosting/deployment/index.mdx b/apps/docs/content/docs/self-hosting/deployment/index.mdx index d7b516d..6f664d3 100644 --- a/apps/docs/content/docs/self-hosting/deployment/index.mdx +++ b/apps/docs/content/docs/self-hosting/deployment/index.mdx @@ -1,6 +1,6 @@ --- title: Deployment -description: Deploy NexaSign using Docker, Docker Compose, or Kubernetes. +description: Deploy NexaFile using Docker, Docker Compose, or Kubernetes. --- | Method | Best For | Difficulty | diff --git a/apps/docs/content/docs/self-hosting/deployment/kubernetes.mdx b/apps/docs/content/docs/self-hosting/deployment/kubernetes.mdx index f70e2fb..78c4d56 100644 --- a/apps/docs/content/docs/self-hosting/deployment/kubernetes.mdx +++ b/apps/docs/content/docs/self-hosting/deployment/kubernetes.mdx @@ -1,6 +1,6 @@ --- title: Kubernetes -description: Deploy NexaSign on Kubernetes for production environments requiring high availability, auto-scaling, and enterprise-grade infrastructure. +description: Deploy NexaFile on Kubernetes for production environments requiring high availability, auto-scaling, and enterprise-grade infrastructure. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -26,7 +26,7 @@ kubectl get nodes ## Architecture Overview -A typical NexaSign Kubernetes deployment consists of: +A typical NexaFile Kubernetes deployment consists of: ```mermaid flowchart TD @@ -41,7 +41,7 @@ flowchart TD ## Namespace Setup -Create a dedicated namespace for NexaSign: +Create a dedicated namespace for NexaFile: ```yaml # namespace.yaml @@ -128,7 +128,7 @@ data: NEXT_PRIVATE_SMTP_TRANSPORT: 'smtp-auth' NEXT_PRIVATE_SMTP_HOST: 'smtp.example.com' NEXT_PRIVATE_SMTP_PORT: '587' - NEXT_PRIVATE_SMTP_FROM_NAME: 'NexaSign' + NEXT_PRIVATE_SMTP_FROM_NAME: 'NexaFile' NEXT_PRIVATE_SMTP_FROM_ADDRESS: 'noreply@example.com' NEXT_PRIVATE_INTERNAL_WEBAPP_URL: 'http://localhost:3000' NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH: '/opt/nexasign/cert.p12' @@ -143,7 +143,7 @@ kubectl apply -f configmap.yaml ## Deployment -Create the NexaSign Deployment: +Create the NexaFile Deployment: ```yaml # deployment.yaml @@ -465,7 +465,7 @@ spec: backups, and point-in-time recovery that managed services provide. -Update your NexaSign secret to use the in-cluster database: +Update your NexaFile secret to use the in-cluster database: ```yaml NEXT_PRIVATE_DATABASE_URL: 'postgresql://nexasign:your-secure-password@postgres.nexasign.svc.cluster.local:5432/nexasign' @@ -474,7 +474,7 @@ NEXT_PRIVATE_DIRECT_DATABASE_URL: 'postgresql://nexasign:your-secure-password@po ## Persistent Storage -NexaSign stores documents in the database by default. For high-volume deployments, configure S3-compatible storage. +NexaFile stores documents in the database by default. For high-volume deployments, configure S3-compatible storage. ### S3 Configuration @@ -500,7 +500,7 @@ See [Storage Configuration](/docs/self-hosting/configuration/storage) for detail ### Horizontal Pod Autoscaler (HPA) -Scale NexaSign based on CPU and memory utilization: +Scale NexaFile based on CPU and memory utilization: ```yaml # hpa.yaml @@ -696,7 +696,7 @@ data: NEXT_PRIVATE_SMTP_TRANSPORT: 'smtp-auth' NEXT_PRIVATE_SMTP_HOST: 'smtp.example.com' NEXT_PRIVATE_SMTP_PORT: '587' - NEXT_PRIVATE_SMTP_FROM_NAME: 'NexaSign' + NEXT_PRIVATE_SMTP_FROM_NAME: 'NexaFile' NEXT_PRIVATE_SMTP_FROM_ADDRESS: 'noreply@example.com' NEXT_PRIVATE_INTERNAL_WEBAPP_URL: 'http://localhost:3000' NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH: '/opt/nexasign/cert.p12' diff --git a/apps/docs/content/docs/self-hosting/deployment/manual.mdx b/apps/docs/content/docs/self-hosting/deployment/manual.mdx index 2c7e7b0..6972245 100644 --- a/apps/docs/content/docs/self-hosting/deployment/manual.mdx +++ b/apps/docs/content/docs/self-hosting/deployment/manual.mdx @@ -1,6 +1,6 @@ --- title: Manual Deployment -description: Deploy NexaSign on a Linux server without Docker using Node.js and systemd. +description: Deploy NexaFile on a Linux server without Docker using Node.js and systemd. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -52,12 +52,12 @@ NEXT_PUBLIC_WEBAPP_URL="https://your-domain.com" NEXT_PRIVATE_INTERNAL_WEBAPP_URL="http://localhost:3000" NEXT_PRIVATE_DATABASE_URL="postgresql://user:password@localhost:5432/nexasign" NEXT_PRIVATE_DIRECT_DATABASE_URL="postgresql://user:password@localhost:5432/nexasign" -NEXT_PRIVATE_SMTP_FROM_NAME="NexaSign" +NEXT_PRIVATE_SMTP_FROM_NAME="NexaFile" NEXT_PRIVATE_SMTP_FROM_ADDRESS="noreply@your-domain.com" ``` - If you use a reverse proxy in front of NexaSign, set `NEXT_PUBLIC_WEBAPP_URL` to the public URL + If you use a reverse proxy in front of NexaFile, set `NEXT_PUBLIC_WEBAPP_URL` to the public URL that users will access. @@ -93,13 +93,13 @@ PORT=3500 ## Run as a systemd Service -Create a service file to run NexaSign as a background service on Linux: +Create a service file to run NexaFile as a background service on Linux: ```ini # /etc/systemd/system/nexasign.service [Unit] -Description=NexaSign +Description=NexaFile After=network.target [Service] @@ -126,7 +126,7 @@ sudo systemctl start nexasign ## Reverse Proxy with Nginx -A minimal Nginx configuration for proxying to NexaSign: +A minimal Nginx configuration for proxying to NexaFile: ```nginx server { diff --git a/apps/docs/content/docs/self-hosting/getting-started/index.mdx b/apps/docs/content/docs/self-hosting/getting-started/index.mdx index 521155b..b7e070b 100644 --- a/apps/docs/content/docs/self-hosting/getting-started/index.mdx +++ b/apps/docs/content/docs/self-hosting/getting-started/index.mdx @@ -1,6 +1,6 @@ --- title: Getting Started -description: Requirements and quick start guide for self-hosting NexaSign. +description: Requirements and quick start guide for self-hosting NexaFile. --- diff --git a/apps/docs/content/docs/self-hosting/getting-started/quick-start.mdx b/apps/docs/content/docs/self-hosting/getting-started/quick-start.mdx index 753cc3a..a7e33a7 100644 --- a/apps/docs/content/docs/self-hosting/getting-started/quick-start.mdx +++ b/apps/docs/content/docs/self-hosting/getting-started/quick-start.mdx @@ -1,6 +1,6 @@ --- title: Quick Start -description: Get NexaSign running locally in minutes with Docker Compose. +description: Get NexaFile running locally in minutes with Docker Compose. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -60,7 +60,7 @@ The default values work for local development. No changes are required. -### Start NexaSign +### Start NexaFile ```bash docker compose -f docker/development/compose.yml up -d diff --git a/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx b/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx index e5f023d..dceef60 100644 --- a/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx +++ b/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx @@ -1,13 +1,13 @@ --- title: Requirements -description: System requirements and prerequisites for self-hosting NexaSign. +description: System requirements and prerequisites for self-hosting NexaFile. --- import { Callout } from 'fumadocs-ui/components/callout'; ## What You Need -NexaSign requires the following external services: +NexaFile requires the following external services: | Service | Purpose | Minimum Version | | ------------- | ---------------------------- | --------------- | @@ -17,9 +17,9 @@ NexaSign requires the following external services: ### PostgreSQL Database -NexaSign uses PostgreSQL for all data storage including documents, users, and audit logs. You cannot use MySQL, SQLite, or other databases. +NexaFile uses PostgreSQL for all data storage including documents, users, and audit logs. You cannot use MySQL, SQLite, or other databases. -NexaSign requires two connection strings: +NexaFile requires two connection strings: - **Pooled connection** (`NEXT_PRIVATE_DATABASE_URL`) - For general application queries - **Direct connection** (`NEXT_PRIVATE_DIRECT_DATABASE_URL`) - For migrations and operations that require a direct connection @@ -28,7 +28,7 @@ If you're not using a connection pooler (like PgBouncer), both can point to the ### Email Server -NexaSign sends transactional emails for: +NexaFile sends transactional emails for: - Document signing requests - Signing reminders @@ -51,7 +51,7 @@ Supported transports: ### Reverse Proxy -For production deployments, place NexaSign behind a reverse proxy such as: +For production deployments, place NexaFile behind a reverse proxy such as: - nginx - Caddy @@ -59,7 +59,7 @@ For production deployments, place NexaSign behind a reverse proxy such as: - HAProxy - Cloud load balancers (AWS ALB, GCP Load Balancer, etc.) -The reverse proxy handles SSL/TLS termination and forwards requests to NexaSign on port 3000. +The reverse proxy handles SSL/TLS termination and forwards requests to NexaFile on port 3000. --- @@ -73,7 +73,7 @@ These services are not required but improve functionality or scalability: ### Document Storage -By default, NexaSign stores documents in the PostgreSQL database. For production deployments with significant document volume, use S3-compatible storage: +By default, NexaFile stores documents in the PostgreSQL database. For production deployments with significant document volume, use S3-compatible storage: - Amazon S3 - MinIO @@ -85,9 +85,9 @@ See [Storage Configuration](/docs/self-hosting/configuration/storage) for setup ### Background Jobs -NexaSign processes background jobs (email delivery, document processing) using a PostgreSQL-based queue by default. No additional services are required: the job queue is built into the application and uses your existing database. +NexaFile processes background jobs (email delivery, document processing) using a PostgreSQL-based queue by default. No additional services are required: the job queue is built into the application and uses your existing database. -For production deployments that need higher throughput or more reliable job processing, NexaSign supports [BullMQ](https://docs.bullmq.io/) as an alternative provider. BullMQ requires a **Redis** instance (v6.2+). Set `NEXT_PRIVATE_JOBS_PROVIDER=bullmq` and configure `NEXT_PRIVATE_REDIS_URL`. +For production deployments that need higher throughput or more reliable job processing, NexaFile supports [BullMQ](https://docs.bullmq.io/) as an alternative provider. BullMQ requires a **Redis** instance (v6.2+). Set `NEXT_PRIVATE_JOBS_PROVIDER=bullmq` and configure `NEXT_PRIVATE_REDIS_URL`. For managed/cloud deployments, [Inngest](https://www.inngest.com/) is also supported as a job provider. Set `NEXT_PRIVATE_JOBS_PROVIDER=inngest` and configure `INNGEST_EVENT_KEY` and `INNGEST_SIGNING_KEY`. @@ -133,7 +133,7 @@ If building from source (not using Docker images): ## Supported Platforms -NexaSign runs on: +NexaFile runs on: - **Linux** - Any modern distribution (Ubuntu, Debian, CentOS, Alpine) - **Docker** - Official images available on DockerHub and GitHub Container Registry @@ -164,7 +164,7 @@ Before proceeding to deployment, confirm you have: - [ ] PostgreSQL 14+ database accessible - [ ] SMTP credentials or email provider API key - [ ] Signing certificate (`.p12`) for document signing — see [Tips](/docs/self-hosting/getting-started/tips) -- [ ] Domain name for your NexaSign instance +- [ ] Domain name for your NexaFile instance - [ ] SSL certificate (or reverse proxy that handles SSL) - [ ] Server meeting minimum hardware requirements @@ -172,6 +172,6 @@ Before proceeding to deployment, confirm you have: ## See Also -- [Quick Start](/docs/self-hosting/getting-started/quick-start) - Deploy NexaSign with Docker in 5 minutes +- [Quick Start](/docs/self-hosting/getting-started/quick-start) - Deploy NexaFile with Docker in 5 minutes - [Docker Compose](/docs/self-hosting/deployment/docker-compose) - Production setup with Docker Compose - [Environment Variables](/docs/self-hosting/configuration/environment) - Full configuration reference diff --git a/apps/docs/content/docs/self-hosting/getting-started/tips.mdx b/apps/docs/content/docs/self-hosting/getting-started/tips.mdx index 3a4a719..7141e8c 100644 --- a/apps/docs/content/docs/self-hosting/getting-started/tips.mdx +++ b/apps/docs/content/docs/self-hosting/getting-started/tips.mdx @@ -1,6 +1,6 @@ --- title: Tips & Common Pitfalls -description: Practical advice for running NexaSign in production. +description: Practical advice for running NexaFile in production. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -8,11 +8,11 @@ import { Callout } from 'fumadocs-ui/components/callout'; ## Always Configure a Signing Certificate - This is the single most common issue when self-hosting NexaSign. Without a signing certificate, + This is the single most common issue when self-hosting NexaFile. Without a signing certificate, the application starts normally but document signing fails. -NexaSign does **not** bundle a [signing certificate](/docs/self-hosting/configuration/signing-certificate) in the Docker image. You must provide one yourself using one of two methods: +NexaFile does **not** bundle a [signing certificate](/docs/self-hosting/configuration/signing-certificate) in the Docker image. You must provide one yourself using one of two methods: ### Volume Mount (Recommended) @@ -51,7 +51,7 @@ NEXT_PRIVATE_SIGNING_PASSPHRASE=your-certificate-password ### Verify Your Certificate -After starting NexaSign, check the certificate status endpoint: +After starting NexaFile, check the certificate status endpoint: ```bash curl http://localhost:3000/api/certificate-status @@ -69,13 +69,13 @@ Certificates without a password cause signing to fail with: Error: Failed to get private key bags ``` -Always set a password when creating your `.p12` certificate. When using OpenSSL, set the password during the export step and provide it to NexaSign via `NEXT_PRIVATE_SIGNING_PASSPHRASE`. +Always set a password when creating your `.p12` certificate. When using OpenSSL, set the password during the export step and provide it to NexaFile via `NEXT_PRIVATE_SIGNING_PASSPHRASE`. --- ## Use the Health Check Endpoints -NexaSign exposes two endpoints for monitoring: +NexaFile exposes two endpoints for monitoring: | Endpoint | Purpose | | ------------------------- | ------------------------------------ | @@ -114,7 +114,7 @@ The Docker container runs `prisma migrate deploy` every time it starts. This mea ## Set Internal Webapp URL for Background Jobs -Background jobs work by NexaSign sending HTTP requests to itself. If your reverse proxy or network setup causes issues with the app reaching its own public URL, set the internal URL: +Background jobs work by NexaFile sending HTTP requests to itself. If your reverse proxy or network setup causes issues with the app reaching its own public URL, set the internal URL: ```bash NEXT_PRIVATE_INTERNAL_WEBAPP_URL=http://localhost:3000 @@ -146,7 +146,7 @@ See [Storage Configuration](/docs/self-hosting/configuration/storage) for full s ## Background Jobs -NexaSign uses a PostgreSQL-based job queue by default (`local` provider). No Redis or external message broker is required for basic deployments. +NexaFile uses a PostgreSQL-based job queue by default (`local` provider). No Redis or external message broker is required for basic deployments. For production workloads, consider switching to **Inngest** (managed) or **BullMQ** (self-hosted with Redis) for better reliability and throughput. @@ -156,7 +156,7 @@ See [Background Jobs Configuration](/docs/self-hosting/configuration/background- ## Docker File Permissions -The NexaSign container runs as a non-root user (UID 1001). If you mount files into the container (certificates, configuration), ensure they're readable: +The NexaFile container runs as a non-root user (UID 1001). If you mount files into the container (certificates, configuration), ensure they're readable: ```bash # On the host, before mounting diff --git a/apps/docs/content/docs/self-hosting/index.mdx b/apps/docs/content/docs/self-hosting/index.mdx index fc8b458..e8c1340 100644 --- a/apps/docs/content/docs/self-hosting/index.mdx +++ b/apps/docs/content/docs/self-hosting/index.mdx @@ -1,6 +1,6 @@ --- title: Self-Hosting -description: Deploy and manage your own NexaSign instance for complete control over your data, compliance, and customization. +description: Deploy and manage your own NexaFile instance for complete control over your data, compliance, and customization. --- ## Getting Started @@ -100,7 +100,7 @@ Choose a deployment method based on your needs: ## Quick Start -Get NexaSign running locally in under 5 minutes: +Get NexaFile running locally in under 5 minutes: ```bash git clone https://github.com/NexaStack-Software/NexaSign.git @@ -117,7 +117,7 @@ See the [Quick Start guide](/docs/self-hosting/getting-started/quick-start) for ## Enterprise Edition -Self-hosted NexaSign includes full core functionality under the AGPL-3.0 license. If you need enterprise features such as SSO, embed authoring white label, or 21 CFR Part 11 compliance, you can activate them with a license key. +Self-hosted NexaFile includes full core functionality under the AGPL-3.0 license. If you need enterprise features such as SSO, embed authoring white label, or 21 CFR Part 11 compliance, you can activate them with a license key. See [Enterprise Edition](/docs/policies/enterprise-edition) for details and [Licenses](/docs/policies/licenses) for a comparison. @@ -128,12 +128,12 @@ See [Enterprise Edition](/docs/policies/enterprise-edition) for details and [Lic diff --git a/apps/docs/content/docs/self-hosting/maintenance/backups.mdx b/apps/docs/content/docs/self-hosting/maintenance/backups.mdx index 1f26af6..273cb0e 100644 --- a/apps/docs/content/docs/self-hosting/maintenance/backups.mdx +++ b/apps/docs/content/docs/self-hosting/maintenance/backups.mdx @@ -1,6 +1,6 @@ --- title: Backups -description: Backup strategies for NexaSign data. +description: Backup strategies for NexaFile data. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -9,7 +9,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## What to Back Up -NexaSign stores data in three locations: +NexaFile stores data in three locations: | Component | Location | Contains | | --------------------- | ----------------------------- | -------------------------------------------------- | @@ -199,7 +199,7 @@ For disaster recovery, enable cross-region replication on your S3 bucket. This a ## Automated Backup Script -Create a script to back up all NexaSign components: +Create a script to back up all NexaFile components: @@ -226,7 +226,7 @@ S3_BUCKET="your-nexasign-bucket" # Create backup directory mkdir -p "$BACKUP_DIR/$TIMESTAMP" -echo "Starting NexaSign backup: $TIMESTAMP" +echo "Starting NexaFile backup: $TIMESTAMP" # Database backup echo "Backing up database..." @@ -353,7 +353,7 @@ Create `/etc/systemd/system/nexasign-backup.service`: ```ini [Unit] -Description=NexaSign Backup +Description=NexaFile Backup [Service] Type=oneshot @@ -365,7 +365,7 @@ Create `/etc/systemd/system/nexasign-backup.timer`: ```ini [Unit] -Description=Daily NexaSign Backup +Description=Daily NexaFile Backup [Timer] OnCalendar=*-*-* 02:00:00 @@ -450,7 +450,7 @@ aws s3 sync /backup/nexasign/documents/ s3://your-nexasign-bucket {/* prettier-ignore */} -### Stop NexaSign +### Stop NexaFile ```bash docker compose stop nexasign @@ -482,7 +482,7 @@ aws s3 sync /backup/documents/ s3://your-bucket -### Start NexaSign +### Start NexaFile ```bash docker compose start nexasign diff --git a/apps/docs/content/docs/self-hosting/maintenance/index.mdx b/apps/docs/content/docs/self-hosting/maintenance/index.mdx index f6c3228..78b9d06 100644 --- a/apps/docs/content/docs/self-hosting/maintenance/index.mdx +++ b/apps/docs/content/docs/self-hosting/maintenance/index.mdx @@ -1,6 +1,6 @@ --- title: Maintenance -description: Upgrade, backup, and troubleshoot your self-hosted NexaSign instance. +description: Upgrade, backup, and troubleshoot your self-hosted NexaFile instance. --- diff --git a/apps/docs/content/docs/self-hosting/maintenance/troubleshooting.mdx b/apps/docs/content/docs/self-hosting/maintenance/troubleshooting.mdx index 2101b6c..ea16690 100644 --- a/apps/docs/content/docs/self-hosting/maintenance/troubleshooting.mdx +++ b/apps/docs/content/docs/self-hosting/maintenance/troubleshooting.mdx @@ -1,6 +1,6 @@ --- title: Troubleshooting -description: Diagnose and resolve common issues with your self-hosted NexaSign instance, organized by component. +description: Diagnose and resolve common issues with your self-hosted NexaFile instance, organized by component. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -55,7 +55,7 @@ docker logs --tail 100 nexasign ### Health Checks -NexaSign exposes a health endpoint to verify the application is running: +NexaFile exposes a health endpoint to verify the application is running: ```bash curl http://localhost:3000/api/health @@ -232,7 +232,7 @@ netstat -tlnp | grep 3000 Stop the conflicting service - Change NexaSign's port mapping: `-p 3001:3000` + Change NexaFile's port mapping: `-p 3001:3000` @@ -690,7 +690,7 @@ openssl pkcs12 -in certificate.p12 -nokeys | openssl x509 -noout -dates Generate a new certificate or obtain a renewed one from your CA - Update the certificate file and restart NexaSign + Update the certificate file and restart NexaFile @@ -1115,7 +1115,7 @@ Gather this information before seeking support: {/* prettier-ignore */} - **NexaSign version:** + **NexaFile version:** ```bash docker inspect nexasign --format='{{.Config.Image}}' @@ -1139,7 +1139,7 @@ docker inspect nexasign --format='{{.Config.Image}}' ### Community Support - **[GitHub Discussions](https://github.com/NexaStack-Software/NexaSign/discussions)** -- **[Discord](https://github.com/NexaStack-Software/NexaSign/discussions)**: Join the NexaSign community Discord +- **[Discord](https://github.com/NexaStack-Software/NexaSign/discussions)**: Join the NexaFile community Discord - **[GitHub Issues](https://github.com/NexaStack-Software/NexaSign/issues)**: For confirmed bugs, open an issue ### Reporting Bugs @@ -1155,7 +1155,7 @@ When reporting bugs, include: Steps to reproduce - NexaSign version + NexaFile version Relevant logs (redact sensitive information) diff --git a/apps/docs/content/docs/self-hosting/maintenance/upgrades.mdx b/apps/docs/content/docs/self-hosting/maintenance/upgrades.mdx index 894d6ff..d892ace 100644 --- a/apps/docs/content/docs/self-hosting/maintenance/upgrades.mdx +++ b/apps/docs/content/docs/self-hosting/maintenance/upgrades.mdx @@ -1,6 +1,6 @@ --- title: Upgrades -description: Upgrade your self-hosted NexaSign installation to get the latest features, security patches, and bug fixes. +description: Upgrade your self-hosted NexaFile installation to get the latest features, security patches, and bug fixes. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -10,7 +10,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Version Policy -NexaSign follows [Semantic Versioning](https://semver.org/): +NexaFile follows [Semantic Versioning](https://semver.org/): | Version Type | Format | Description | | ------------ | ------- | ------------------------------------------ | @@ -37,7 +37,7 @@ For production deployments, pin to a specific version tag to avoid unexpected up ### View Current Version -Check your running NexaSign version: +Check your running NexaFile version: @@ -340,7 +340,7 @@ curl http://localhost:3000/api/health ## Database Migrations -NexaSign runs database migrations automatically when the container starts. No manual intervention is required. +NexaFile runs database migrations automatically when the container starts. No manual intervention is required. ### Migration Process diff --git a/apps/docs/content/docs/users/documents/advanced/ai-detection.mdx b/apps/docs/content/docs/users/documents/advanced/ai-detection.mdx index c92621c..224a21f 100644 --- a/apps/docs/content/docs/users/documents/advanced/ai-detection.mdx +++ b/apps/docs/content/docs/users/documents/advanced/ai-detection.mdx @@ -1,6 +1,6 @@ --- title: AI Recipient & Field Detection -description: Use NexaSign's AI helpers to detect recipients and fields in draft documents. +description: Use NexaFile's AI helpers to detect recipients and fields in draft documents. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -10,7 +10,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Overview -NexaSign can suggest recipients and place fields automatically using Google Vertex AI (Gemini). The feature is optional and only available when your organisation or team has **AI Features** enabled. Documents are processed securely and providers do not retain your data for training. +NexaFile can suggest recipients and place fields automatically using Google Vertex AI (Gemini). The feature is optional and only available when your organisation or team has **AI Features** enabled. Documents are processed securely and providers do not retain your data for training. ## Requirements diff --git a/apps/docs/content/docs/users/documents/advanced/default-recipients.mdx b/apps/docs/content/docs/users/documents/advanced/default-recipients.mdx index 0fb1c16..00e78b9 100644 --- a/apps/docs/content/docs/users/documents/advanced/default-recipients.mdx +++ b/apps/docs/content/docs/users/documents/advanced/default-recipients.mdx @@ -8,7 +8,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Overview -NexaSign allows you to set default recipients for your documents. This is useful when you require specific recipients to be added to every document you send. +NexaFile allows you to set default recipients for your documents. This is useful when you require specific recipients to be added to every document you send. You can add default recipients with the same roles as the recipients you can add when sending a document: diff --git a/apps/docs/content/docs/users/documents/advanced/document-visibility.mdx b/apps/docs/content/docs/users/documents/advanced/document-visibility.mdx index 6fb0466..41c6766 100644 --- a/apps/docs/content/docs/users/documents/advanced/document-visibility.mdx +++ b/apps/docs/content/docs/users/documents/advanced/document-visibility.mdx @@ -53,7 +53,7 @@ New documents use the team's default. You can change the visibility to any optio You can change visibility at any time by editing the document and choosing a different option. -![A screenshot of the NexaSign's document editor page where you can update the document visibility](/teams/document-visibility-settings.webp) +![A screenshot of the NexaFile's document editor page where you can update the document visibility](/teams/document-visibility-settings.webp) Updating the default document visibility in the team's general preferences will not affect the diff --git a/apps/docs/content/docs/users/documents/advanced/pdf-placeholders.mdx b/apps/docs/content/docs/users/documents/advanced/pdf-placeholders.mdx index 9660741..e6a83ef 100644 --- a/apps/docs/content/docs/users/documents/advanced/pdf-placeholders.mdx +++ b/apps/docs/content/docs/users/documents/advanced/pdf-placeholders.mdx @@ -1,6 +1,6 @@ --- title: PDF Placeholders -description: Learn how to use placeholder text in your PDFs for automatic field placement in NexaSign. +description: Learn how to use placeholder text in your PDFs for automatic field placement in NexaFile. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -8,11 +8,11 @@ import { Callout } from 'fumadocs-ui/components/callout'; ## Overview -NexaSign can automatically detect placeholder text in your PDF documents and create fields at those locations. This allows you to prepare documents in your preferred editing tool (Word, Google Docs, etc.) with placeholders that become signature fields when uploaded. +NexaFile can automatically detect placeholder text in your PDF documents and create fields at those locations. This allows you to prepare documents in your preferred editing tool (Word, Google Docs, etc.) with placeholders that become signature fields when uploaded. ## How It Works -When you upload a PDF, NexaSign scans for text matching the placeholder pattern `{{...}}`. Each placeholder can specify: +When you upload a PDF, NexaFile scans for text matching the placeholder pattern `{{...}}`. Each placeholder can specify: 1. **Field type**: What kind of field to create (signature, name, email, etc.) 2. **Recipient**: Which signer the field belongs to (r1, r2, etc.) @@ -68,7 +68,7 @@ Recipients are identified using `r1`, `r2`, `r3`, etc. The number corresponds to - `r2` - Second recipient - `r3` - Third recipient -When you upload a PDF with placeholders, NexaSign will: +When you upload a PDF with placeholders, NexaFile will: 1. Create placeholder recipients for each unique identifier found (e.g., `r1`, `r2`) 2. You can then update these with real email addresses before sending diff --git a/apps/docs/content/docs/users/documents/direct-links.mdx b/apps/docs/content/docs/users/documents/direct-links.mdx index 2c5be46..647e798 100644 --- a/apps/docs/content/docs/users/documents/direct-links.mdx +++ b/apps/docs/content/docs/users/documents/direct-links.mdx @@ -53,7 +53,7 @@ In the modal that appears, click **Enable direct link** to proceed. Choose which recipient in your template will use the direct link: - **Select an existing recipient**: Pick from recipients already defined in your template -- **Create one automatically**: NexaSign creates a new "Direct Link Recipient" for you +- **Create one automatically**: NexaFile creates a new "Direct Link Recipient" for you ![Choose direct link recipient](/direct-links/choose-direct-link-recipient-nexasign.webp) @@ -93,7 +93,7 @@ When someone opens your direct link: 3. They complete any required fields (signature, text, checkboxes, etc.) 4. After signing, they receive a copy of the completed document via email -If the recipient has a NexaSign account with the email they entered, the document also appears in their Documents dashboard. +If the recipient has a NexaFile account with the email they entered, the document also appears in their Documents dashboard. --- @@ -139,7 +139,7 @@ To permanently remove a direct link: ## Add Direct Links to Your Profile -You can showcase templates with direct links on your public NexaSign profile: +You can showcase templates with direct links on your public NexaFile profile: {/* prettier-ignore */} @@ -157,7 +157,7 @@ You can showcase templates with direct links on your public NexaSign profile: -![NexaSign profile with direct links](/direct-links/nexasign-profile.webp) +![NexaFile profile with direct links](/direct-links/nexasign-profile.webp) This is useful for freelancers, consultants, or businesses who want clients to easily access common agreements. diff --git a/apps/docs/content/docs/users/documents/upload.mdx b/apps/docs/content/docs/users/documents/upload.mdx index 201eb7f..5dcaf71 100644 --- a/apps/docs/content/docs/users/documents/upload.mdx +++ b/apps/docs/content/docs/users/documents/upload.mdx @@ -1,6 +1,6 @@ --- title: Upload Documents -description: Upload documents to NexaSign to prepare them for signing. Covers supported formats, file size limits, and upload methods. +description: Upload documents to NexaFile to prepare them for signing. Covers supported formats, file size limits, and upload methods. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -17,7 +17,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; | Password-protected PDFs | Not supported | - NexaSign does not support password-protected or encrypted PDF files. Remove encryption before + NexaFile does not support password-protected or encrypted PDF files. Remove encryption before uploading. @@ -100,7 +100,7 @@ All files in the same upload become part of the same envelope and share the same When you upload a document: -1. **Processing**: NexaSign validates the PDF and extracts page information +1. **Processing**: NexaFile validates the PDF and extracts page information 2. **Draft created**: A new document is created in `Draft` status 3. **Editor opens**: You're taken to the document editor to add recipients and fields diff --git a/apps/docs/content/docs/users/getting-started/create-account.mdx b/apps/docs/content/docs/users/getting-started/create-account.mdx index fd787e2..e75115b 100644 --- a/apps/docs/content/docs/users/getting-started/create-account.mdx +++ b/apps/docs/content/docs/users/getting-started/create-account.mdx @@ -1,6 +1,6 @@ --- title: Create an Account -description: Sign up for NexaSign and configure your profile. +description: Sign up for NexaFile and configure your profile. --- import { Callout } from 'fumadocs-ui/components/callout'; @@ -8,7 +8,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Choose a Plan -NexaSign offers four plans: +NexaFile offers four plans: | Plan | Best for | | ---------- | ---------------------------------------------- | @@ -71,7 +71,7 @@ After signing up, secure your account with additional authentication methods. Go to **Settings > Security** to enable 2FA for an extra layer of protection. - ![NexaSign account security page showing security options](/get-started-images/nexasign-account-security-page.webp) + ![NexaFile account security page showing security options](/get-started-images/nexasign-account-security-page.webp) diff --git a/apps/docs/content/docs/users/getting-started/index.mdx b/apps/docs/content/docs/users/getting-started/index.mdx index 7971b4a..cddff47 100644 --- a/apps/docs/content/docs/users/getting-started/index.mdx +++ b/apps/docs/content/docs/users/getting-started/index.mdx @@ -6,7 +6,7 @@ description: Create your account and send your first document for signing. diff --git a/apps/docs/content/docs/users/organisations/email-domains.mdx b/apps/docs/content/docs/users/organisations/email-domains.mdx index ef8f7d1..3e93f94 100644 --- a/apps/docs/content/docs/users/organisations/email-domains.mdx +++ b/apps/docs/content/docs/users/organisations/email-domains.mdx @@ -1,6 +1,6 @@ --- title: Email Domains -description: Learn how to create and manage email domains in NexaSign. +description: Learn how to create and manage email domains in NexaFile. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -9,7 +9,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Overview -Email Domains allow you to send emails to recipients from your own domain instead of the default NexaSign email address. +Email Domains allow you to send emails to recipients from your own domain instead of the default NexaFile email address. **Enterprise Only**: Email Domains is only available to Enterprise customers and custom plans @@ -21,7 +21,7 @@ Before setting up email domains, ensure you have: - An Enterprise subscription - Access to your domain's DNS settings -- Access to your NexaSign organisation as an admin or manager +- Access to your NexaFile organisation as an admin or manager {/* prettier-ignore */} @@ -38,7 +38,7 @@ Navigate to your Organisation email domains settings page and click the "Add Ema ### Configure DNS records -After adding your domain, NexaSign will provide you with the following required DNS records that need to be configured on your domain: +After adding your domain, NexaFile will provide you with the following required DNS records that need to be configured on your domain: - **SPF Record**: Specifies which servers are authorized to send emails from your domain - **DKIM Record**: Provides email authentication and prevents tampering @@ -57,7 +57,7 @@ Configure these records in your domain's DNS settings according to their specifi ### Verify domain configuration -Once you've added the DNS records, return to the NexaSign email domains settings page and click the "Verify" button. +Once you've added the DNS records, return to the NexaFile email domains settings page and click the "Verify" button. This will trigger a verification process which will check if the DNS records are properly configured. If successful, the domain will be marked as "Active". diff --git a/apps/docs/content/docs/users/organisations/members.mdx b/apps/docs/content/docs/users/organisations/members.mdx index db7a680..1607854 100644 --- a/apps/docs/content/docs/users/organisations/members.mdx +++ b/apps/docs/content/docs/users/organisations/members.mdx @@ -24,9 +24,9 @@ Organisation members have different permission levels that determine what they c ## Transferring Organisation Ownership -Organisation ownership cannot be transferred through the regular organisation settings. Only a NexaSign instance administrator can transfer ownership through the admin panel. +Organisation ownership cannot be transferred through the regular organisation settings. Only a NexaFile instance administrator can transfer ownership through the admin panel. -If you are using NexaSign Cloud, contact support to request an ownership transfer. If you are self-hosting, an instance administrator can follow the steps below. +If you are using NexaFile Cloud, contact support to request an ownership transfer. If you are self-hosting, an instance administrator can follow the steps below. The target user must already be a member of the organisation. @@ -132,7 +132,7 @@ When someone invites you to an organisation: Check your email for the invitation and click the link. - Sign in or create a NexaSign account. + Sign in or create a NexaFile account. Accept the invitation. diff --git a/apps/docs/content/docs/users/organisations/overview.mdx b/apps/docs/content/docs/users/organisations/overview.mdx index 0e22f02..6bd854b 100644 --- a/apps/docs/content/docs/users/organisations/overview.mdx +++ b/apps/docs/content/docs/users/organisations/overview.mdx @@ -1,6 +1,6 @@ --- title: Overview -description: Organisations are the top-level entity in NexaSign, containing teams, members, and shared settings. +description: Organisations are the top-level entity in NexaFile, containing teams, members, and shared settings. --- import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; @@ -9,7 +9,7 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## What are Organisations? -Organisations are the top-level entity in NexaSign's hierarchy. Each organisation can contain multiple teams, and each team can have multiple members. +Organisations are the top-level entity in NexaFile's hierarchy. Each organisation can contain multiple teams, and each team can have multiple members. ![Organisations diagram](/organisations/organisations-basic-diagram.webp) @@ -37,7 +37,7 @@ This structure provides: Navigate to the organisation section and click **Create Organisation**. -![Create organisation in NexaSign dashboard](/organisations/organisations-create.webp) +![Create organisation in NexaFile dashboard](/organisations/organisations-create.webp) diff --git a/apps/docs/content/docs/users/organisations/preferences/branding.mdx b/apps/docs/content/docs/users/organisations/preferences/branding.mdx index 6559257..ef71ad6 100644 --- a/apps/docs/content/docs/users/organisations/preferences/branding.mdx +++ b/apps/docs/content/docs/users/organisations/preferences/branding.mdx @@ -49,7 +49,7 @@ Go to your organisation settings and select the **Branding** tab under **Prefere Select **Yes** from the **Enable Custom Branding** dropdown. -When disabled, recipients see the default NexaSign branding. +When disabled, recipients see the default NexaFile branding. @@ -112,7 +112,7 @@ Override organisation branding for specific teams in **Team Settings > Preferenc | Setting | Behavior | | ----------------------------- | ---------------------------------------------------------------- | | **Yes** | Enable branding with team-specific logo and details | -| **No** | Disable branding for this team (show default NexaSign branding) | +| **No** | Disable branding for this team (show default NexaFile branding) | | **Inherit from organisation** | Use the organisation's branding settings | diff --git a/apps/docs/content/docs/users/organisations/single-sign-on/configuration.mdx b/apps/docs/content/docs/users/organisations/single-sign-on/configuration.mdx index 72db280..3a3f355 100644 --- a/apps/docs/content/docs/users/organisations/single-sign-on/configuration.mdx +++ b/apps/docs/content/docs/users/organisations/single-sign-on/configuration.mdx @@ -12,7 +12,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; ## Supported Providers -NexaSign supports any identity provider that implements the OpenID Connect (OIDC) protocol. Common providers include: +NexaFile supports any identity provider that implements the OpenID Connect (OIDC) protocol. Common providers include: - Microsoft Entra ID (formerly Azure AD) - Google Workspace @@ -49,7 +49,7 @@ At the top of the SSO settings page, you'll find the **Redirect URI** and **Requ In your identity provider's admin console, create a new OIDC application with: -- **Redirect URI**: The value from the NexaSign SSO settings page +- **Redirect URI**: The value from the NexaFile SSO settings page - **Scopes**: `openid`, `email`, `profile` After creating the application, note down: @@ -63,7 +63,7 @@ After creating the application, note down: ### Enter SSO configuration -Back in NexaSign, enter the following: +Back in NexaFile, enter the following: - **Issuer URL**: Your provider's OpenID Connect discovery endpoint - **Client ID**: The application client ID from your provider @@ -143,7 +143,7 @@ When a user signs in through your SSO portal for the first time: ### Verify identity -NexaSign verifies their identity with your provider. +NexaFile verifies their identity with your provider. @@ -169,7 +169,7 @@ They can immediately access organisation documents. Users provisioned through SSO: - Cannot change their email address -- Cannot set a NexaSign password (they must use SSO) +- Cannot set a NexaFile password (they must use SSO) - Are removed from SSO access if removed from your identity provider ## Signing In with SSO @@ -177,7 +177,7 @@ Users provisioned through SSO: Once SSO is enabled, your organisation's SSO portal URL is displayed at the top of the SSO settings page. Share this URL with your members so they can sign in through your identity provider. - SSO-only enforcement is not currently available. Users who have an existing NexaSign account with a password can still sign in with their original method in addition to SSO. + SSO-only enforcement is not currently available. Users who have an existing NexaFile account with a password can still sign in with their original method in addition to SSO. ## Troubleshooting @@ -201,7 +201,7 @@ Once SSO is enabled, your organisation's SSO portal URL is displayed at the top {/* prettier-ignore */} - - Copy the redirect URI exactly from NexaSign's SSO settings + - Copy the redirect URI exactly from NexaFile's SSO settings - Check for trailing slashes. They must match exactly. @@ -217,7 +217,7 @@ Once SSO is enabled, your organisation's SSO portal URL is displayed at the top {/* prettier-ignore */} - If a user already has a NexaSign account with the same email, their existing account will be linked to your team and they can sign in through your SSO portal going forward. + If a user already has a NexaFile account with the same email, their existing account will be linked to your team and they can sign in through your SSO portal going forward. diff --git a/apps/docs/content/docs/users/organisations/single-sign-on/index.mdx b/apps/docs/content/docs/users/organisations/single-sign-on/index.mdx index 925272a..d49d630 100644 --- a/apps/docs/content/docs/users/organisations/single-sign-on/index.mdx +++ b/apps/docs/content/docs/users/organisations/single-sign-on/index.mdx @@ -7,7 +7,7 @@ import { Callout } from 'fumadocs-ui/components/callout'; SSO is only available on the Enterprise plan. -NexaSign supports any identity provider that implements the OpenID Connect (OIDC) protocol. +NexaFile supports any identity provider that implements the OpenID Connect (OIDC) protocol. --- diff --git a/apps/docs/content/docs/users/organisations/single-sign-on/microsoft-entra-id.mdx b/apps/docs/content/docs/users/organisations/single-sign-on/microsoft-entra-id.mdx index 0ad0559..67a148a 100644 --- a/apps/docs/content/docs/users/organisations/single-sign-on/microsoft-entra-id.mdx +++ b/apps/docs/content/docs/users/organisations/single-sign-on/microsoft-entra-id.mdx @@ -10,12 +10,12 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Overview -Microsoft Entra ID (formerly Azure Active Directory) is a popular identity provider for enterprise SSO. This guide will walk you through creating an app registration and configuring it for use with your NexaSign SSO portal. +Microsoft Entra ID (formerly Azure Active Directory) is a popular identity provider for enterprise SSO. This guide will walk you through creating an app registration and configuring it for use with your NexaFile SSO portal. ## Prerequisites - Access to Microsoft Entra ID (Azure AD) admin center -- Access to your NexaSign organisation as an administrator or manager +- Access to your NexaFile organisation as an administrator or manager Each user in your Azure AD will need an email associated with it. @@ -46,9 +46,9 @@ Microsoft Entra ID (formerly Azure Active Directory) is a popular identity provi Fill in the registration form with the following details: -- **Name**: Your preferred name (e.g. `NexaSign SSO Portal`) +- **Name**: Your preferred name (e.g. `NexaFile SSO Portal`) - **Supported account types**: Choose based on your needs -- **Redirect URI (Web)**: Found in the NexaSign SSO portal settings page +- **Redirect URI (Web)**: Found in the NexaFile SSO portal settings page Click "Register" to create the app registration. @@ -57,7 +57,7 @@ Click "Register" to create the app registration. ### Get client ID -After registration, you'll be taken to the app's overview page. The **Application (client) ID** is displayed prominently - this is your Client ID for NexaSign. +After registration, you'll be taken to the app's overview page. The **Application (client) ID** is displayed prominently - this is your Client ID for NexaFile. @@ -66,7 +66,7 @@ After registration, you'll be taken to the app's overview page. The **Applicatio - In the left sidebar, click on "Certificates & secrets" - Click "New client secret" -- Add a description (e.g., "NexaSign SSO Secret") +- Add a description (e.g., "NexaFile SSO Secret") - Choose an expiration period (recommended 12-24 months) - Click "Add" @@ -108,9 +108,9 @@ Copy the **OpenID Connect metadata document** value. -## Configure NexaSign SSO Portal +## Configure NexaFile SSO Portal -Now you have all the information needed to configure your NexaSign SSO portal: +Now you have all the information needed to configure your NexaFile SSO portal: | Field | Value | | ----------------- | ------------------------------------------------------------------- | diff --git a/apps/docs/content/docs/users/settings/api-tokens.mdx b/apps/docs/content/docs/users/settings/api-tokens.mdx index 43d24b5..e0a68ea 100644 --- a/apps/docs/content/docs/users/settings/api-tokens.mdx +++ b/apps/docs/content/docs/users/settings/api-tokens.mdx @@ -1,13 +1,13 @@ --- title: API Tokens -description: Create and manage API tokens for programmatic access to your NexaSign account. +description: Create and manage API tokens for programmatic access to your NexaFile account. --- import { Callout } from 'fumadocs-ui/components/callout'; ## Overview -API tokens allow external applications to access your NexaSign account programmatically. Tokens can be scoped to your personal account or to a specific team. +API tokens allow external applications to access your NexaFile account programmatically. Tokens can be scoped to your personal account or to a specific team. For detailed instructions on creating and managing API tokens, see the [Authentication](/docs/developers/getting-started/authentication) guide in the developer documentation. diff --git a/apps/docs/content/docs/users/settings/delete-account.mdx b/apps/docs/content/docs/users/settings/delete-account.mdx index be6e4f2..d27c509 100644 --- a/apps/docs/content/docs/users/settings/delete-account.mdx +++ b/apps/docs/content/docs/users/settings/delete-account.mdx @@ -1,6 +1,6 @@ --- title: Delete Account -description: Permanently delete your NexaSign account and all associated data. +description: Permanently delete your NexaFile account and all associated data. --- import { Callout } from 'fumadocs-ui/components/callout'; diff --git a/apps/docs/content/docs/users/settings/public-profile.mdx b/apps/docs/content/docs/users/settings/public-profile.mdx index 0715d37..a9ffacc 100644 --- a/apps/docs/content/docs/users/settings/public-profile.mdx +++ b/apps/docs/content/docs/users/settings/public-profile.mdx @@ -57,7 +57,7 @@ Display templates on your public profile so visitors can sign documents directly Links](/docs/users/documents/direct-links) to learn more. -A free NexaSign account gives you 5 free signatures per month. +A free NexaFile account gives you 5 free signatures per month. --- diff --git a/apps/docs/content/docs/users/settings/security.mdx b/apps/docs/content/docs/users/settings/security.mdx index ceae761..c975ee9 100644 --- a/apps/docs/content/docs/users/settings/security.mdx +++ b/apps/docs/content/docs/users/settings/security.mdx @@ -91,7 +91,7 @@ Two-factor authentication adds a second layer of security by requiring a code fr ## Recovery Codes -Recovery codes let you access your account if you lose access to your authenticator app. When you enable 2FA, NexaSign generates a set of backup codes. +Recovery codes let you access your account if you lose access to your authenticator app. When you enable 2FA, NexaFile generates a set of backup codes. ### View Recovery Codes @@ -121,7 +121,7 @@ Recovery codes let you access your account if you lose access to your authentica ## Passkeys -Passkeys provide passwordless authentication using biometrics, hardware security keys, or password managers. You can use passkeys to sign in to NexaSign and to authenticate when signing documents. +Passkeys provide passwordless authentication using biometrics, hardware security keys, or password managers. You can use passkeys to sign in to NexaFile and to authenticate when signing documents. ![Passkeys management page](/get-started-images/nexasign-passkeys-page.webp) diff --git a/apps/docs/public/logo.png b/apps/docs/public/logo.png index 4813aaa..49f53e2 100644 Binary files a/apps/docs/public/logo.png and b/apps/docs/public/logo.png differ diff --git a/apps/docs/src/app/(home)/page.tsx b/apps/docs/src/app/(home)/page.tsx index a518702..7c32d4c 100644 --- a/apps/docs/src/app/(home)/page.tsx +++ b/apps/docs/src/app/(home)/page.tsx @@ -12,9 +12,9 @@ import { } from 'lucide-react'; export const metadata: Metadata = { - title: 'NexaSign Docs', + title: 'NexaFile Docs', description: - 'The official documentation for NexaSign, the open-source document signing platform. Send documents for signatures, integrate with the API, or self-host with full control.', + 'The official documentation for NexaFile, the open-source document lifecycle platform. Find documents, send them for signatures, integrate with the API, or self-host with full control.', }; export default function HomePage() { @@ -22,10 +22,10 @@ export default function HomePage() {
{/* Hero */}
-

NexaSign Dokumentation

+

NexaFile Dokumentation

- The open-source document signing platform. Send documents for signatures, integrate with - your apps, or self-host with full control. + The open-source document lifecycle platform. Find documents, send them for signatures, + integrate with your apps, or self-host with full control.

Self-Hosting Guide

- Deploy your own NexaSign instance with Docker, Kubernetes, or Railway. + Deploy your own NexaFile instance with Docker, Kubernetes, or Railway.

Deploy now → @@ -239,7 +239,7 @@ export default function HomePage() {

Join the Community

- NexaSign is open source. Contribute, ask questions, or share feedback. + NexaFile is open source. Contribute, ask questions, or share feedback.

diff --git a/apps/docs/src/app/layout.tsx b/apps/docs/src/app/layout.tsx index ca33f27..ad1458a 100644 --- a/apps/docs/src/app/layout.tsx +++ b/apps/docs/src/app/layout.tsx @@ -13,13 +13,13 @@ const inter = Inter({ export const metadata: Metadata = { metadataBase: new URL('https://nexasign.nexastack.co/docs'), title: { - template: '%s | NexaSign Docs', - default: 'NexaSign Docs', + template: '%s | NexaFile Docs', + default: 'NexaFile Docs', }, description: - 'The official documentation for NexaSign, the open-source document signing platform.', + 'The official documentation for NexaFile, the open-source document lifecycle platform.', openGraph: { - siteName: 'NexaSign Docs', + siteName: 'NexaFile Docs', type: 'website', }, twitter: { diff --git a/apps/docs/src/app/og/docs/[...slug]/route.tsx b/apps/docs/src/app/og/docs/[...slug]/route.tsx index 3982861..8461d1d 100644 --- a/apps/docs/src/app/og/docs/[...slug]/route.tsx +++ b/apps/docs/src/app/og/docs/[...slug]/route.tsx @@ -73,8 +73,7 @@ export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[... gap: '16px', }} > - {/* eslint-disable-next-line @next/next/no-img-element */} - NexaSign + NexaFile - NexaSign + NexaFile ), }, diff --git a/apps/remix/app/components/dialogs/account-delete-dialog.tsx b/apps/remix/app/components/dialogs/account-delete-dialog.tsx index 9192a93..b82a0bf 100644 --- a/apps/remix/app/components/dialogs/account-delete-dialog.tsx +++ b/apps/remix/app/components/dialogs/account-delete-dialog.tsx @@ -109,7 +109,7 @@ export const AccountDeleteDialog = ({ className }: AccountDeleteDialogProps) => - NexaSign will delete{' '} + NexaFile will delete{' '} all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account. diff --git a/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx b/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx index 4e3c0ce..c04caa1 100644 --- a/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx +++ b/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx @@ -333,7 +333,7 @@ export const EnvelopeDistributeDialog = ({ ))} - NexaSign + NexaFile diff --git a/apps/remix/app/components/dialogs/webhook-create-dialog.tsx b/apps/remix/app/components/dialogs/webhook-create-dialog.tsx index 945df7d..b4e5ab7 100644 --- a/apps/remix/app/components/dialogs/webhook-create-dialog.tsx +++ b/apps/remix/app/components/dialogs/webhook-create-dialog.tsx @@ -141,7 +141,7 @@ export const WebhookCreateDialog = ({ trigger, ...props }: WebhookCreateDialogPr - The URL for NexaSign to send webhook events to. + The URL for NexaFile to send webhook events to. @@ -219,7 +219,7 @@ export const WebhookCreateDialog = ({ trigger, ...props }: WebhookCreateDialogPr A secret that will be sent to your URL so you can verify that the request - has been sent by NexaSign. + has been sent by NexaFile. diff --git a/apps/remix/app/components/dialogs/webhook-edit-dialog.tsx b/apps/remix/app/components/dialogs/webhook-edit-dialog.tsx index 4301695..33aedf1 100644 --- a/apps/remix/app/components/dialogs/webhook-edit-dialog.tsx +++ b/apps/remix/app/components/dialogs/webhook-edit-dialog.tsx @@ -121,7 +121,7 @@ export const WebhookEditDialog = ({ trigger, webhook, ...props }: WebhookEditDia - The URL for NexaSign to send webhook events to. + The URL for NexaFile to send webhook events to. @@ -197,7 +197,7 @@ export const WebhookEditDialog = ({ trigger, webhook, ...props }: WebhookEditDia A secret that will be sent to your URL so you can verify that the request - has been sent by NexaSign. + has been sent by NexaFile. diff --git a/apps/remix/app/components/embed/embed-document-completed.tsx b/apps/remix/app/components/embed/embed-document-completed.tsx index f299d57..e2df3ba 100644 --- a/apps/remix/app/components/embed/embed-document-completed.tsx +++ b/apps/remix/app/components/embed/embed-document-completed.tsx @@ -19,7 +19,7 @@ export const EmbedDocumentCompleted = ({ name, signature }: EmbedDocumentComplet
diff --git a/apps/remix/app/components/general/admin-license-card.tsx b/apps/remix/app/components/general/admin-license-card.tsx index ebeb80a..01dcec0 100644 --- a/apps/remix/app/components/general/admin-license-card.tsx +++ b/apps/remix/app/components/general/admin-license-card.tsx @@ -95,7 +95,7 @@ export const AdminLicenseCard = ({ licenseData }: AdminLicenseCardProps) => {

- NexaSign License + NexaFile License

{match(license.status) diff --git a/apps/remix/app/components/general/admin-license-status-banner.tsx b/apps/remix/app/components/general/admin-license-status-banner.tsx index e53b70b..f4eab33 100644 --- a/apps/remix/app/components/general/admin-license-status-banner.tsx +++ b/apps/remix/app/components/general/admin-license-status-banner.tsx @@ -43,12 +43,12 @@ export const AdminLicenseStatusBanner = ({ license }: AdminLicenseStatusBannerPr .with('UNAUTHORIZED', () => license ? ( - Invalid License Type - Your NexaSign instance is using features that are not part + Invalid License Type - Your NexaFile instance is using features that are not part of your license. ) : ( - Missing License - Your NexaSign instance is using features that require a license. + Missing License - Your NexaFile instance is using features that require a license. ), ) diff --git a/apps/remix/app/components/general/app-header.tsx b/apps/remix/app/components/general/app-header.tsx index 5d0b2b9..3cc3195 100644 --- a/apps/remix/app/components/general/app-header.tsx +++ b/apps/remix/app/components/general/app-header.tsx @@ -59,23 +59,23 @@ export const Header = ({ className, ...props }: HeaderProps) => { {...props} >
- {/* NexaSign-Logo: fertig gesetzte Wortmarke als Bild. + {/* NexaFile-Logo: fertig gesetzte Wortmarke als Bild. 60 px hoch, 1x + 2x via srcset, WebP mit PNG-Fallback. Identisch zur PHP-Nav (templates/vorlagen-index/_nav.php). */} NexaSign diff --git a/apps/remix/app/components/general/app-nav-desktop.tsx b/apps/remix/app/components/general/app-nav-desktop.tsx index 02123fc..80bdd6a 100644 --- a/apps/remix/app/components/general/app-nav-desktop.tsx +++ b/apps/remix/app/components/general/app-nav-desktop.tsx @@ -52,15 +52,18 @@ export const AppNavDesktop = ({ return []; } + // NexaFile-Hauptnavigation: Erstellen → Finden → Signieren → Archivieren. + // Erstellen und Archivieren sind PHP-Bereiche, bleiben aber Teil derselben + // Nutzerführung. return [ + { + href: `/t/${teamUrl}/find-documents`, + label: msg`Dokumente finden`, + }, { href: `/t/${teamUrl}/documents`, - label: msg`Documents`, + label: msg`Dokumente signieren`, }, - // NexaSign-Templates (interne Signier-Vorlagen) sind weiter per URL - // erreichbar (/t//templates), stehen aber nicht in der Haupt-Nav — - // dort führt der Eintrag „Vorlagen" rechts daneben auf die öffentliche - // Vorlagen-Bibliothek /vorlagen/. ]; }, [currentTeam, organisations]); @@ -81,11 +84,26 @@ export const AppNavDesktop = ({ exit={{ opacity: 0 }} className="flex items-baseline gap-x-6" > - {menuNavigationLinks.map(({ href, label }) => ( + {/* 1. Erstellen — externer PHP-Bereich /vorlagen/ */} + + Dokumente erstellen + + + {/* 2. Finden — interne Remix-Route */} + {menuNavigationLinks.slice(0, 1).map(({ href, label }) => ( ))} - {/* NexaSign: „Vorlagen" und „GoBD" — externe Bereiche, gleicher Stil wie die Remix-Links */} - - Vorlagen - + + {/* 3. Signieren — interne Remix-Route */} + {menuNavigationLinks.slice(1).map(({ href, label }) => ( + + {_(label)} + + ))} + + {/* 4. Archivieren — externer PHP-Bereich /vorlagen/gobd/ */} - GoBD + Dokumente archivieren )} diff --git a/apps/remix/app/components/general/app-nav-mobile.tsx b/apps/remix/app/components/general/app-nav-mobile.tsx index 2111777..19f5613 100644 --- a/apps/remix/app/components/general/app-nav-mobile.tsx +++ b/apps/remix/app/components/general/app-nav-mobile.tsx @@ -60,14 +60,27 @@ export const AppNavMobile = ({ isMenuOpen, onMenuOpenChange }: AppNavMobileProps ]; } + // NexaFile-Hauptnavigation in 4 Schritten: Erstellen → Finden → + // Signieren → Archivieren. Templates (Signier-Vorlagen) bleiben per Direkt-URL + // /t//templates erreichbar, stehen aber nicht in der Haupt-Nav. return [ + { + href: '/vorlagen/', + text: t`Dokumente erstellen`, + external: true, + }, + { + href: `/t/${teamUrl}/find-documents`, + text: t`Dokumente finden`, + }, { href: `/t/${teamUrl}/documents`, - text: t`Documents`, + text: t`Dokumente signieren`, }, { - href: `/t/${teamUrl}/templates`, - text: t`Templates`, + href: '/vorlagen/gobd/', + text: t`Dokumente archivieren`, + external: true, }, { href: '/inbox', @@ -86,7 +99,7 @@ export const AppNavMobile = ({ isMenuOpen, onMenuOpenChange }: AppNavMobileProps NexaSign Logo
- {menuNavigationLinks.map(({ href, text }) => ( - handleMenuItemClick()} - > - {text} - {href === '/inbox' && unreadCountData && unreadCountData.count > 0 && ( - - {unreadCountData.count > 99 ? '99+' : unreadCountData.count} - - )} - - ))} + {menuNavigationLinks.map((link) => + 'external' in link && link.external ? ( + handleMenuItemClick()} + > + {link.text} + + ) : ( + handleMenuItemClick()} + > + {link.text} + {link.href === '/inbox' && unreadCountData && unreadCountData.count > 0 && ( + + {unreadCountData.count > 99 ? '99+' : unreadCountData.count} + + )} + + ), + )} + + + +
diff --git a/apps/remix/app/routes/_authenticated+/documents.tsx b/apps/remix/app/routes/_authenticated+/documents.tsx new file mode 100644 index 0000000..9c9d430 --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/documents.tsx @@ -0,0 +1,13 @@ +import { redirect } from 'react-router'; + +import { formatDocumentsPath } from '@nexasign/lib/utils/teams'; + +import { getPreferredTeamUrlOrRedirect } from '~/utils/redirect-to-preferred-team.server'; + +import type { Route } from './+types/documents'; + +export async function loader({ request }: Route.LoaderArgs) { + const teamUrl = await getPreferredTeamUrlOrRedirect(request); + + throw redirect(formatDocumentsPath(teamUrl)); +} diff --git a/apps/remix/app/routes/_authenticated+/find-documents.tsx b/apps/remix/app/routes/_authenticated+/find-documents.tsx new file mode 100644 index 0000000..5ab174f --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/find-documents.tsx @@ -0,0 +1,11 @@ +import { redirect } from 'react-router'; + +import { getPreferredTeamUrlOrRedirect } from '~/utils/redirect-to-preferred-team.server'; + +import type { Route } from './+types/find-documents'; + +export async function loader({ request }: Route.LoaderArgs) { + const teamUrl = await getPreferredTeamUrlOrRedirect(request); + + throw redirect(`/t/${teamUrl}/find-documents`); +} diff --git a/apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx b/apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx index 8797841..066f76d 100644 --- a/apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx +++ b/apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx @@ -62,7 +62,7 @@ export default function SupportPage() {

- Read our documentation to get started with NexaSign. + Read our documentation to get started with NexaFile.

{organisation && IS_BILLING_ENABLED() && subscriptionStatus && ( diff --git a/apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx b/apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx new file mode 100644 index 0000000..7929d9e --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx @@ -0,0 +1,499 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { useMemo, useState } from 'react'; + +import { msg } from '@lingui/core/macro'; +import { useLingui } from '@lingui/react'; +import { Trans } from '@lingui/react/macro'; +import { + AlertCircleIcon, + ArrowLeftIcon, + CheckCircleIcon, + Loader2Icon, + PlayCircleIcon, + SquareIcon, + TrashIcon, + XCircleIcon, +} from 'lucide-react'; +import { Link, useNavigate, useParams } from 'react-router'; + +import { trpc } from '@nexasign/trpc/react'; +import type { + TSyncRun, + TSyncRunStatus, +} from '@nexasign/trpc/server/sources-router/schema'; +import { Button } from '@nexasign/ui/primitives/button'; +import { Card } from '@nexasign/ui/primitives/card'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@nexasign/ui/primitives/dialog'; +import { Input } from '@nexasign/ui/primitives/input'; +import { Label } from '@nexasign/ui/primitives/label'; +import { Skeleton } from '@nexasign/ui/primitives/skeleton'; +import { useToast } from '@nexasign/ui/primitives/use-toast'; + +import { SettingsHeader } from '~/components/general/settings-header'; +import { appMetaTags } from '~/utils/meta'; + +export function meta() { + return appMetaTags(msg`Quelle`); +} + +const formatDateTime = (date: Date | null, locale: string): string => { + if (!date) return '–'; + return new Intl.DateTimeFormat(locale, { + dateStyle: 'medium', + timeStyle: 'short', + }).format(date); +}; + +const formatDateRange = (from: Date, to: Date, locale: string): string => { + const fmt = new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' }); + return `${fmt.format(from)} – ${fmt.format(to)}`; +}; + +const toIsoDate = (d: Date): string => d.toISOString().slice(0, 10); + +// Schnellauswahl-Buttons. Liefert [from, to] in lokaler Zeit, danach in UTC ohne +// Drift, weil wir die Range als reine Datums-Eingabe verstehen. +const buildPreset = ( + preset: 'last-month' | 'last-quarter' | 'last-year' | 'previous-year', +): { from: Date; to: Date } => { + const now = new Date(); + if (preset === 'last-month') { + const from = new Date(now.getFullYear(), now.getMonth() - 1, 1); + const to = new Date(now.getFullYear(), now.getMonth(), 1); + return { from, to }; + } + if (preset === 'last-quarter') { + const startMonth = Math.floor(now.getMonth() / 3) * 3 - 3; + const from = new Date(now.getFullYear(), startMonth, 1); + const to = new Date(now.getFullYear(), startMonth + 3, 1); + return { from, to }; + } + if (preset === 'last-year') { + const from = new Date(now.getFullYear() - 1, 0, 1); + const to = new Date(now.getFullYear(), 0, 1); + return { from, to }; + } + // previous-year + const from = new Date(now.getFullYear() - 2, 0, 1); + const to = new Date(now.getFullYear() - 1, 0, 1); + return { from, to }; +}; + +const SyncRunStatusIcon = ({ status }: { status: TSyncRunStatus }) => { + if (status === 'RUNNING' || status === 'PENDING') { + return ; + } + if (status === 'SUCCESS') { + return ; + } + if (status === 'CANCELLED') { + return ; + } + return ; +}; + +const SyncRunRow = ({ + run, + locale, + onCancel, + isCancelling, +}: { + run: TSyncRun; + locale: string; + onCancel: (id: string) => void; + isCancelling: boolean; +}) => { + const isActive = run.status === 'PENDING' || run.status === 'RUNNING'; + return ( + +
+ +
+

{formatDateRange(run.rangeFrom, run.rangeTo, locale)}

+ {run.status === 'SUCCESS' || run.status === 'CANCELLED' || isActive ? ( +

+ + {run.documentsAuto} importiert, {run.documentsManual} manuell,{' '} + {run.documentsIgnored} ignoriert · {run.mailsChecked} Mails geprüft + +

+ ) : null} + {run.status === 'FAILED' && run.errorMessage && ( +

{run.errorMessage}

+ )} +

+ {isActive ? ( + Gestartet {formatDateTime(run.startedAt, locale)} + ) : ( + Beendet {formatDateTime(run.finishedAt, locale)} + )} +

+
+
+ {isActive && ( + + )} +
+ ); +}; + +export default function SettingsSourceDetail() { + const params = useParams(); + const sourceId = params.id ?? ''; + const navigate = useNavigate(); + const { _, i18n } = useLingui(); + const { toast } = useToast(); + + const utils = trpc.useUtils(); + const { data: sources, isLoading } = trpc.sources.listSources.useQuery(); + const source = sources?.find((s) => s.id === sourceId); + + const { data: runs } = trpc.sources.listSyncRuns.useQuery( + { sourceId, limit: 10 }, + { + enabled: Boolean(sourceId && source), + // Pollt alle 3 Sekunden, solange ein Lauf RUNNING/PENDING ist. + refetchInterval: (query) => { + const items = query.state.data ?? []; + return items.some((r) => r.status === 'RUNNING' || r.status === 'PENDING') ? 3000 : false; + }, + }, + ); + + const activeRun = useMemo( + () => runs?.find((r) => r.status === 'RUNNING' || r.status === 'PENDING') ?? null, + [runs], + ); + + const [from, setFrom] = useState(''); + const [to, setTo] = useState(''); + + const applyPreset = (preset: 'last-month' | 'last-quarter' | 'last-year' | 'previous-year') => { + const range = buildPreset(preset); + setFrom(toIsoDate(range.from)); + setTo(toIsoDate(range.to)); + }; + + const test = trpc.sources.testSource.useMutation({ + onSuccess: (result) => { + toast({ + title: result.ok ? _(msg`Verbindung erfolgreich`) : _(msg`Verbindung fehlgeschlagen`), + description: result.error, + variant: result.ok ? 'default' : 'destructive', + }); + }, + onError: (err) => + toast({ + title: _(msg`Test fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }), + }); + + const startSyncRun = trpc.sources.startSyncRun.useMutation({ + onSuccess: () => { + void utils.sources.listSyncRuns.invalidate(); + void utils.sources.listSources.invalidate(); + void utils.discovery.findDocuments.invalidate(); + toast({ + title: _(msg`Sync-Lauf gestartet`), + description: _(msg`Der Fortschritt wird unten angezeigt.`), + }); + setFrom(''); + setTo(''); + }, + onError: (err) => + toast({ + title: _(msg`Sync-Lauf konnte nicht starten`), + description: err.message, + variant: 'destructive', + }), + }); + + const cancelSyncRun = trpc.sources.cancelSyncRun.useMutation({ + onSuccess: () => { + void utils.sources.listSyncRuns.invalidate(); + toast({ title: _(msg`Abbruch wird ausgeführt`) }); + }, + onError: (err) => + toast({ + title: _(msg`Abbruch fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }), + }); + + const reactivate = trpc.sources.reactivateSource.useMutation({ + onSuccess: () => { + void utils.sources.listSources.invalidate(); + toast({ title: _(msg`Quelle reaktiviert`) }); + }, + onError: (err) => + toast({ + title: _(msg`Reaktivieren fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }), + }); + + const remove = trpc.sources.deleteSource.useMutation({ + onSuccess: () => { + void utils.sources.listSources.invalidate(); + void utils.discovery.findDocuments.invalidate(); + toast({ title: _(msg`Quelle entfernt`) }); + void navigate('/settings/sources'); + }, + onError: (err) => + toast({ + title: _(msg`Entfernen fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }), + }); + + if (isLoading) { + return ( +
+ + +
+ ); + } + + if (!source) { + return ( + + +
+

+ Quelle nicht gefunden +

+

+ Diese Quelle existiert nicht oder wurde gelöscht. +

+
+ +
+ ); + } + + const isSuspended = source.lastSyncStatus === 'SUSPENDED'; + const canStartRun = !isSuspended && !activeRun && from && to && !startSyncRun.isPending; + + return ( +
+ + + + + {isSuspended && ( + +
+

+ Diese Quelle ist gesperrt. +

+

+ + Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren. + +

+ {source.lastSyncError &&

{source.lastSyncError}

} +
+ +
+ )} + + {/* Sync-Lauf starten */} + +

+ Neuen Sync-Lauf starten +

+

+ + Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den + Eingang importiert. Bereits importierte Belege werden automatisch übersprungen. + +

+ +
+ + + + +
+ +
+
+ + setFrom(e.target.value)} + /> +
+
+ + setTo(e.target.value)} /> +
+
+ +
+ + + +
+ + {activeRun && ( +

+ + Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen. + +

+ )} +
+ + {/* Run-History */} +
+

+ Vergangene Sync-Läufe +

+
+ {!runs && ( + <> + + + + )} + {runs && runs.length === 0 && ( + + Noch keine Sync-Läufe. Starten Sie oben einen Lauf. + + )} + {runs?.map((run) => ( + cancelSyncRun.mutate({ syncRunId: id })} + isCancelling={cancelSyncRun.isPending} + /> + ))} +
+
+ + {/* Konto-Aktionen */} +
+ + + + + + + + Quelle wirklich entfernen? + + + + Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht + mehr eingelesen. + + + + + + + + +
+
+ ); +} diff --git a/apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx b/apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx new file mode 100644 index 0000000..98666a4 --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { useState } from 'react'; + +import { msg } from '@lingui/core/macro'; +import { useLingui } from '@lingui/react'; +import { Trans } from '@lingui/react/macro'; +import { + AlertCircleIcon, + CheckCircleIcon, + ClockIcon, + Loader2Icon, + PauseCircleIcon, + PlugIcon, + PlusIcon, +} from 'lucide-react'; +import { Link } from 'react-router'; + +import { trpc } from '@nexasign/trpc/react'; +import type { TSourceListItem } from '@nexasign/trpc/server/sources-router/schema'; +import { Badge } from '@nexasign/ui/primitives/badge'; +import { Button } from '@nexasign/ui/primitives/button'; +import { Card } from '@nexasign/ui/primitives/card'; +import { Checkbox } from '@nexasign/ui/primitives/checkbox'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@nexasign/ui/primitives/dialog'; +import { Input } from '@nexasign/ui/primitives/input'; +import { Label } from '@nexasign/ui/primitives/label'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@nexasign/ui/primitives/select'; +import { Skeleton } from '@nexasign/ui/primitives/skeleton'; +import { useToast } from '@nexasign/ui/primitives/use-toast'; + +import { SettingsHeader } from '~/components/general/settings-header'; +import { appMetaTags } from '~/utils/meta'; + +export function meta() { + return appMetaTags(msg`Quellen`); +} + +const StatusBadge = ({ source }: { source: TSourceListItem }) => { + if (source.lastSyncStatus === 'SUSPENDED') { + return ( + + + Gesperrt + + ); + } + if (source.lastSyncStatus === 'FAILED') { + return ( + + + Fehler + + ); + } + if (source.lastSyncStatus === 'SUCCESS') { + return ( + + + Aktiv + + ); + } + return ( + + + Wartet auf ersten Sync + + ); +}; + +const SourceRow = ({ source }: { source: TSourceListItem }) => ( + + +
+

{source.label}

+

+ IMAP-Konto · Team: {source.teamName} + {source.lastSyncError && ( + <> + · + {source.lastSyncError} + + )} +

+
+ +
+ +); + +type AvailableTeam = { + id: number; + name: string; + url: string; + organisationName: string; +}; + +const AddImapSourceDialog = ({ + capabilities, + availableTeams, + onCreated, +}: { + capabilities: + | { allowedHosts: string[]; customHostsAllowed: boolean; maxAccountsPerUser: number } + | undefined; + availableTeams: AvailableTeam[]; + onCreated: () => void; +}) => { + const { _ } = useLingui(); + const { toast } = useToast(); + const [open, setOpen] = useState(false); + const [label, setLabel] = useState(''); + const [teamId, setTeamId] = useState( + availableTeams[0] ? String(availableTeams[0].id) : '', + ); + const [host, setHost] = useState(''); + const [customHost, setCustomHost] = useState(''); + const [port, setPort] = useState(993); + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const [tlsVerify, setTlsVerify] = useState(true); + + const utils = trpc.useUtils(); + const create = trpc.sources.createImapSource.useMutation({ + onSuccess: () => { + void utils.sources.listSources.invalidate(); + void utils.discovery.findDocuments.invalidate(); + toast({ + title: _(msg`Quelle hinzugefügt`), + description: _(msg`Erster Sync läuft im Hintergrund.`), + }); + onCreated(); + setOpen(false); + setLabel(''); + setHost(''); + setCustomHost(''); + setUsername(''); + setPassword(''); + }, + onError: (err) => { + toast({ + title: _(msg`Speichern fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }); + }, + }); + + const test = trpc.sources.testSource.useMutation({ + onSuccess: (result) => { + toast({ + title: result.ok ? _(msg`Verbindung erfolgreich`) : _(msg`Verbindung fehlgeschlagen`), + description: result.error, + variant: result.ok ? 'default' : 'destructive', + }); + }, + onError: (err) => { + toast({ + title: _(msg`Test fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }); + }, + }); + + const effectiveHost = host === '__custom__' ? customHost.trim() : host; + const canSubmit = + label.trim() && teamId && effectiveHost && username.trim() && password && !create.isPending; + + const buildConfig = () => ({ + host: effectiveHost, + port, + username: username.trim(), + password, + tlsVerify, + }); + + return ( + + + + + + + + IMAP-Konto verbinden + + + + Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten + werden verschlüsselt gespeichert und sind nur für Sie sichtbar. + + + + +
+
+ + setLabel(e.target.value)} + /> +
+ +
+ + +

+ + In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht + ändern — bei Bedarf eine neue Quelle anlegen. + +

+
+ +
+ + + {host === '__custom__' && ( + setCustomHost(e.target.value)} + /> + )} +
+ +
+
+ + +
+
+ +
+
+ + {!tlsVerify && ( + + + Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. + Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat. + + + )} + +
+ + setUsername(e.target.value)} + /> +
+ +
+ + setPassword(e.target.value)} + /> +

+ + Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das + Login-Passwort zu nutzen. + +

+
+
+ + + + + +
+
+ ); +}; + +export default function SettingsSourcesIndex() { + const { _ } = useLingui(); + + const { data: sources, isLoading } = trpc.sources.listSources.useQuery(); + const { data: capabilities } = trpc.sources.getCapabilities.useQuery(); + + const reachedLimit = + capabilities && sources ? sources.length >= capabilities.imap.maxAccountsPerUser : false; + + return ( +
+ + {!reachedLimit && ( + { + // tRPC-Invalidate passiert in der Mutation, hier nichts mehr. + }} + /> + )} + + +
+ {isLoading && ( + <> + + + + )} + + {!isLoading && sources && sources.length === 0 && ( + + +
+

+ Noch keine Quelle verbunden +

+

+ + Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte + Zeiträume. Gefundene Belege legt NexaFile im Eingang ab. + +

+
+
+ )} + + {!isLoading && sources?.map((source) => )} + + {reachedLimit && ( +

+ + Limit erreicht: maximal {capabilities?.imap.maxAccountsPerUser} IMAP-Konten pro Konto. + Bestehende Quelle löschen, um eine neue anzulegen. + +

+ )} +
+
+ ); +} diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx new file mode 100644 index 0000000..c475964 --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { msg } from '@lingui/core/macro'; +import { useLingui } from '@lingui/react'; +import { Trans } from '@lingui/react/macro'; +import { + AlertCircleIcon, + ArchiveIcon, + ArrowLeftIcon, + CheckCircleIcon, + ClockIcon, + DownloadIcon, + ExternalLinkIcon, + FileTextIcon, + HashIcon, + Loader2Icon, + LockIcon, + MailIcon, + PaperclipIcon, + PenLineIcon, + RefreshCwIcon, + XCircleIcon, +} from 'lucide-react'; +import { Link, useNavigate, useParams } from 'react-router'; + +import { trpc } from '@nexasign/trpc/react'; +import type { + TDiscoveryArtifact, + TDiscoveryDocumentAction, +} from '@nexasign/trpc/server/discovery-router/schema'; +import { Badge } from '@nexasign/ui/primitives/badge'; +import { Button } from '@nexasign/ui/primitives/button'; +import { Card } from '@nexasign/ui/primitives/card'; +import { Skeleton } from '@nexasign/ui/primitives/skeleton'; +import { useToast } from '@nexasign/ui/primitives/use-toast'; + +import { appMetaTags } from '~/utils/meta'; + +export function meta() { + return appMetaTags(msg`Beleg-Detail`); +} + +const formatBytes = (bytes: number): string => { + if (bytes < 1024) return `${bytes} B`; + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; + return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; +}; + +const formatDate = (date: Date | null, locale: string): string => { + if (!date) return '–'; + return new Intl.DateTimeFormat(locale, { + dateStyle: 'long', + timeStyle: 'short', + }).format(date); +}; + +const ArtifactRow = ({ artifact }: { artifact: TDiscoveryArtifact }) => { + const Icon = artifact.kind === 'ATTACHMENT' ? PaperclipIcon : FileTextIcon; + return ( +
+ ); +}; + +export default function FindDocumentsDetail() { + const params = useParams(); + const id = params.id ?? ''; + const teamUrl = params.teamUrl ?? ''; + const navigate = useNavigate(); + const { _, i18n } = useLingui(); + const { toast } = useToast(); + + const utils = trpc.useUtils(); + const { data, isLoading } = trpc.discovery.getDocumentDetail.useQuery({ id }); + + const updateStatusMutation = trpc.discovery.updateStatus.useMutation({ + onSuccess: () => { + void utils.discovery.findDocuments.invalidate(); + void utils.discovery.getDocumentDetail.invalidate({ id }); + toast({ title: _(msg`Aktion ausgeführt`) }); + }, + onError: (err) => { + toast({ + title: _(msg`Aktion fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }); + }, + }); + + const handleAction = (action: TDiscoveryDocumentAction) => { + updateStatusMutation.mutate({ id, action }); + }; + + // Re-Sync einer einzelnen Mail aus IMAP — laedt das Archive nach, falls es + // beim Erst-Sync noch keine Archive-Funktion gab oder Files verloren gingen. + const resyncMutation = trpc.discovery.resyncSingle.useMutation({ + onSuccess: (result) => { + if (result.ok) { + toast({ + title: _(msg`Mail erneut aus IMAP geladen`), + description: _(msg`${result.attachmentsAdded} Anhang/Anhänge wieder verfügbar.`), + }); + void utils.discovery.getDocumentDetail.invalidate({ id }); + void utils.discovery.findDocuments.invalidate(); + } else { + toast({ + title: _(msg`Re-Sync fehlgeschlagen`), + description: result.reason, + variant: 'destructive', + }); + } + }, + onError: (err) => { + toast({ + title: _(msg`Re-Sync fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }); + }, + }); + + const createSigningDocumentMutation = trpc.discovery.createSigningDocument.useMutation({ + onSuccess: (result) => { + void utils.discovery.getDocumentDetail.invalidate({ id }); + void utils.discovery.findDocuments.invalidate(); + toast({ + title: result.alreadyExisted + ? _(msg`Signatur-Dokument geöffnet`) + : _(msg`Signatur-Dokument vorbereitet`), + }); + void navigate(`/t/${teamUrl}/documents/${result.envelopeId}/edit`); + }, + onError: (err) => { + toast({ + title: _(msg`Signatur-Dokument konnte nicht vorbereitet werden`), + description: err.message, + variant: 'destructive', + }); + }, + }); + + if (isLoading) { + return ( +
+ + +
+ ); + } + + if (!data) { + return ( +
+ + +

+ Beleg nicht gefunden +

+ +
+
+ ); + } + + const { document: doc, artifacts, absoluteArchivePath, gmailDeepLink } = data; + const isAccepted = Boolean(doc.acceptedAt); + const isPending = updateStatusMutation.isPending; + + return ( +
+
+
+ +

{doc.title}

+
+ {doc.correspondent && {doc.correspondent}} + {formatDate(doc.documentDate ?? doc.capturedAt, i18n.locale)} + {doc.sourceLabel && ( + + + {doc.sourceLabel} + + )} + {isAccepted && ( + + + Akzeptiert · GoBD-gesperrt + + )} +
+
+
+ + {/* Aktions-Buttons */} +
+ {!isAccepted && doc.status === 'inbox' && ( + <> + + + + + )} + {!isAccepted && doc.status === 'pending-manual' && ( + + )} + {isAccepted && doc.status !== 'processed' && ( + + )} + {gmailDeepLink && ( + + )} + {doc.signingEnvelopeId ? ( + + ) : ( + + )} +
+ + {/* Erkannte Felder */} + {(doc.detectedAmount || doc.detectedInvoiceNumber || doc.portalHint) && ( + + {doc.detectedAmount && ( +
+

+ Erkannter Betrag +

+

{doc.detectedAmount}

+
+ )} + {doc.detectedInvoiceNumber && ( +
+

+ Rechnungs-Nr. +

+

{doc.detectedInvoiceNumber}

+
+ )} + {doc.portalHint && ( +
+

+ Portal-Hinweis (Mail enthält) +

+

{doc.portalHint}

+
+ )} +
+ )} + + {/* Mail-Body — als Klartext, niemals dangerouslySetInnerHTML */} + {doc.bodyText && ( + +
+

+ Mail-Inhalt +

+ {doc.bodyHasHtml && ( +

+ + HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline + angezeigt. + +

+ )} +
+
+            {doc.bodyText}
+          
+
+ )} + + {/* Artifact-Liste — nur wenn ueberhaupt Files da sind. Wenn nicht, + zeigen wir einen ehrlichen Hinweis statt eines toten Buttons. */} + {artifacts.length > 0 ? ( +
+
+

+ Dateien im Archiv +

+ {/* Sammel-Download: Anhänge + .eml als ZIP, eigener Ordner-Prefix. + Nutzt denselben Endpoint wie Multi-Select aus der Listen-Ansicht. + Absoluter Pfad — relative URLs resolven hier ungewollt. */} + +
+
+ {artifacts.map((art) => ( + + ))} +
+
+ ) : ( + +

+ + Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des + Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. + Beleg-Hinweis ohne PDF, der zum Portal verweist). + +

+ {/* Re-Sync nur fuer IMAP-Belege anbieten — andere Provider haben + keinen Re-Fetch-Pfad. Knopf laedt eml + Anhaenge nach. */} + {doc.providerSource === 'imap' && ( +
+ + + + Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv. + + +
+ )} +
+ )} + + {/* Server-Pfad-Hinweis fürs FTP/SCP-Reingucken */} + {absoluteArchivePath && ( + +

+ Pfad auf dem Server +

+

{absoluteArchivePath}

+

+ + Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie + benutzen Sie `cp` statt `mv`. + +

+
+ )} +
+ ); +} diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id.artifacts.$artifactId.ts b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id.artifacts.$artifactId.ts new file mode 100644 index 0000000..932a881 --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id.artifacts.$artifactId.ts @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +import { promises as fs } from 'node:fs'; +import path from 'node:path'; + +import { getSession } from '@nexasign/auth/server/lib/utils/get-session'; +import { getAbsoluteArchivePath } from '@nexasign/lib/server-only/sources/archive'; +import { getTeamByUrl } from '@nexasign/lib/server-only/team/get-team'; +import { prisma } from '@nexasign/prisma'; + +import type { Route } from './+types/find-documents.$id.artifacts.$artifactId'; + +const attachmentHeader = (fileName: string): string => { + const safe = fileName.replace(/["\r\n]/g, '_'); + return `attachment; filename="${safe}"`; +}; + +export async function loader({ request, params }: Route.LoaderArgs) { + const { user } = await getSession(request); + const team = await getTeamByUrl({ + userId: user.id, + teamUrl: params.teamUrl, + }); + + const artifact = await prisma.discoveryArtifact.findFirst({ + where: { + id: params.artifactId, + discoveryDocument: { + id: params.id, + teamId: team.id, + OR: [{ providerSource: 'local' }, { uploadedById: user.id }], + }, + }, + include: { + discoveryDocument: { select: { archivePath: true } }, + }, + }); + + if (!artifact || !artifact.discoveryDocument.archivePath) { + throw new Response('Not Found', { status: 404 }); + } + + const archiveDir = path.resolve(getAbsoluteArchivePath(artifact.discoveryDocument.archivePath)); + const filePath = path.resolve(archiveDir, artifact.relativePath); + const archivePrefix = `${archiveDir}${path.sep}`; + + if (!filePath.startsWith(archivePrefix)) { + throw new Response('Invalid artifact path', { status: 400 }); + } + + const content = await fs.readFile(filePath).catch(() => null); + if (!content) { + throw new Response('Not Found', { status: 404 }); + } + + return new Response(content, { + headers: { + 'Content-Type': artifact.contentType, + 'Content-Length': String(content.length), + 'Content-Disposition': attachmentHeader(artifact.fileName), + 'Cache-Control': 'private, no-store', + 'X-Content-Type-Options': 'nosniff', + }, + }); +} diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx new file mode 100644 index 0000000..0271147 --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx @@ -0,0 +1,996 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { useEffect, useState } from 'react'; + +import { msg } from '@lingui/core/macro'; +import { useLingui } from '@lingui/react'; +import { Trans } from '@lingui/react/macro'; +import { + AlertCircleIcon, + ArchiveIcon, + CalendarIcon, + CheckCircleIcon, + ClockIcon, + DownloadIcon, + FileTextIcon, + InboxIcon, + MoreHorizontalIcon, + PaperclipIcon, + PlayIcon, + PlugIcon, + SearchIcon, + Settings2Icon, + XCircleIcon, +} from 'lucide-react'; +import { Link, useParams } from 'react-router'; + +import { trpc } from '@nexasign/trpc/react'; +import type { + TDiscoveryDocumentAction, + TFindDiscoveryDocumentsResponse, +} from '@nexasign/trpc/server/discovery-router/schema'; +import { Badge } from '@nexasign/ui/primitives/badge'; +import { Button } from '@nexasign/ui/primitives/button'; +import { Card } from '@nexasign/ui/primitives/card'; +import { Checkbox } from '@nexasign/ui/primitives/checkbox'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@nexasign/ui/primitives/dropdown-menu'; +import { Input } from '@nexasign/ui/primitives/input'; +import { Skeleton } from '@nexasign/ui/primitives/skeleton'; +import { Tabs, TabsList, TabsTrigger } from '@nexasign/ui/primitives/tabs'; +import { useToast } from '@nexasign/ui/primitives/use-toast'; + +// Vollständiger Status-Enum (matcht das tRPC-Schema). Tabs zeigen aber nur +// die 4 Hauptzustände — IGNORED ist via Filter erreichbar, PROCESSED ist eine +// Sammel-Kategorie. +type DiscoveryStatus = + | 'inbox' + | 'pending-manual' + | 'accepted' + | 'archived' + | 'ignored' + | 'processed'; +// "all" ist die Default-Übersicht — alle Belege auf einen Blick, sortiert nach +// Datum. Die anderen Tabs sind Workflow-Filter. +type DiscoveryTab = 'all' | 'inbox' | 'pending-manual' | 'accepted' | 'archived'; +type Document = TFindDiscoveryDocumentsResponse['documents'][number]; +type Source = TFindDiscoveryDocumentsResponse['sources'][number]; + +const STATUS_TABS: ReadonlyArray<{ value: DiscoveryTab; label: ReturnType }> = [ + { value: 'all', label: msg`Alle` }, + { value: 'inbox', label: msg`Eingang` }, + { value: 'pending-manual', label: msg`Manuell zu ziehen` }, + { value: 'accepted', label: msg`Akzeptiert` }, + { value: 'archived', label: msg`Archiv` }, +]; + +const formatRelativeTime = (date: Date, locale: string): string => { + const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }); + const diffSeconds = Math.round((date.getTime() - Date.now()) / 1000); + const diffMinutes = Math.round(diffSeconds / 60); + const diffHours = Math.round(diffMinutes / 60); + const diffDays = Math.round(diffHours / 24); + if (Math.abs(diffSeconds) < 60) return rtf.format(diffSeconds, 'second'); + if (Math.abs(diffMinutes) < 60) return rtf.format(diffMinutes, 'minute'); + if (Math.abs(diffHours) < 24) return rtf.format(diffHours, 'hour'); + return rtf.format(diffDays, 'day'); +}; + +const formatDate = (date: Date | null, locale: string): string => { + if (!date) return '–'; + return new Intl.DateTimeFormat(locale, { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }).format(date); +}; + +const toDateInputValue = (date: Date): string => date.toISOString().slice(0, 10); + +const addDays = (value: string, days: number): Date => { + const date = new Date(`${value}T00:00:00`); + date.setDate(date.getDate() + days); + return date; +}; + +const StatusIcon = ({ status }: { status: DiscoveryStatus }) => { + if (status === 'pending-manual') return ; + if (status === 'accepted' || status === 'processed') + return ; + if (status === 'archived') return ; + return ; +}; + +const statusLabel = (status: DiscoveryStatus): React.ReactNode => { + switch (status) { + case 'inbox': + return Neu; + case 'pending-manual': + return Manuell; + case 'accepted': + return Akzeptiert; + case 'archived': + return Archiv; + case 'ignored': + return Ignoriert; + case 'processed': + return Verarbeitet; + } +}; + +const DocumentRow = ({ + doc, + locale, + onAction, + isPending, + isSelected, + onToggleSelect, +}: { + doc: Document; + locale: string; + onAction: (id: string, action: TDiscoveryDocumentAction) => void; + isPending: boolean; + isSelected: boolean; + onToggleSelect: (id: string) => void; +}) => ( + +
+ {/* Multi-Select-Checkbox: outside des Detail-Links, damit Klick aufs + Häkchen den User NICHT zur Detail-Seite navigiert. */} +
+ onToggleSelect(doc.id)} + aria-label={`Beleg „${doc.title}" auswählen`} + /> +
+ + {/* Klickbarer Bereich → Detail-Seite. Akzeptieren-/Archivieren-Buttons + liegen ausserhalb dieses Links, damit deren Klicks nicht zur Detail- + Seite navigieren. */} + + +
+

{doc.title}

+
+ {doc.correspondent && {doc.correspondent}} + {doc.detectedInvoiceNumber && ( + {doc.detectedInvoiceNumber} + )} + {formatDate(doc.documentDate ?? doc.capturedAt, locale)} + {/* Anhang-Indikator: nur wenn herunterladbares Archiv vorhanden. + Wenn Mail in der DB ist aber keine Files → kein Icon, nichts + Klickbares — User weiss visuell „hier gibt's nichts zum Laden". */} + {doc.hasArchive && doc.attachmentCount > 0 && ( + 1 ? '"e' : '' + } verfügbar`} + > + + {doc.attachmentCount} + + )} +
+
+ + +
+ + + {statusLabel(doc.status)} + + {doc.status === 'inbox' && ( + <> + + + + + + + onAction(doc.id, 'mark-pending-manual')}> + + Als manuell zu ziehen markieren + + onAction(doc.id, 'archive')}> + + Archivieren + + onAction(doc.id, 'ignore')}> + + Ignorieren + + + + + )} + {doc.status === 'pending-manual' && ( + + )} +
+
+ {doc.tags.length > 0 && ( +
+ {doc.tags.map((tag) => ( + + {tag} + + ))} +
+ )} +
+); + +/** + * Sticky Action-Bar am oberen Listen-Rand, sichtbar sobald >=1 Beleg + * ausgewaehlt ist. Zeigt ehrlich, wie viele der ausgewaehlten Belege + * tatsaechlich Files haben — wenn 0, ist der ZIP-Button disabled. + */ +const BulkActionBar = ({ + selectedCount, + downloadableCount, + onClear, + zipHref, +}: { + selectedCount: number; + downloadableCount: number; + onClear: () => void; + zipHref: string; +}) => { + const noneDownloadable = downloadableCount === 0; + return ( +
+
+

+ {selectedCount} ausgewählt +

+ {downloadableCount < selectedCount && ( +

+ + {downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der + übersprungenen Mails. + +

+ )} +
+
+ {noneDownloadable ? ( + + ) : ( + + )} + +
+
+ ); +}; + +const LoadingList = () => ( +
+ {Array.from({ length: 4 }).map((_, i) => ( + + ))} +
+); + +const NoSourceEmptyState = () => ( + + +
+

+ Verbinden Sie Ihre erste Dokumentenquelle +

+

+ + Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet + haben. + +

+
+ +
+); + +const SourcesStatusBar = ({ sources, locale }: { sources: Source[]; locale: string }) => { + const latestSync = + sources + .map((s) => s.lastSyncAt) + .filter((d): d is Date => d !== null) + .sort((a, b) => b.getTime() - a.getTime())[0] ?? null; + + return ( +
+
+ {latestSync ? ( + <> + + + Letzter Sync: {formatRelativeTime(latestSync, locale)} + + + ) : ( + <> + + + Noch kein Sync gestartet + + + )} +
+ +
+ ); +}; + +const MailboxSearchPanel = ({ + sources, + sourceId, + setSourceId, + fromDate, + setFromDate, + toDate, + setToDate, + searchTerm, + setSearchTerm, + onStart, + isPending, +}: { + sources: Source[]; + sourceId: string; + setSourceId: (value: string) => void; + fromDate: string; + setFromDate: (value: string) => void; + toDate: string; + setToDate: (value: string) => void; + searchTerm: string; + setSearchTerm: (value: string) => void; + onStart: () => void; + isPending: boolean; +}) => ( + +
+
+

+ Postfach durchsuchen +

+

+ + Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt + Mail + Anhänge im Server-Archiv ab. + +

+
+ +
+ +
+ + + + + + + + + +
+
+); + +const NoResultsCard = ({ sources, locale }: { sources: Source[]; locale: string }) => ( +
+ + + +
+

+ Keine Belege im aktuellen Bereich +

+

+ + Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, + um Belege aus Ihrem Postfach einzulesen. + +

+
+ +
+
+); + +// Tabellen-Ansicht für „Akzeptiert" und „Archiv". Im Gegensatz zur Card-Liste +// (die für Eingang+Manuell wegen der Aktions-Buttons sinnvoller ist) brauchen +// wir hier Lese-Übersicht über viele Belege + Export. +const csvEscape = (val: string | null | undefined): string => { + if (val == null) return ''; + if (/[",\n;]/.test(val)) return `"${val.replace(/"/g, '""')}"`; + return val; +}; + +const downloadCsv = (filename: string, rows: string[][]): void => { + const csv = rows.map((row) => row.map(csvEscape).join(';')).join('\n'); + // BOM für Excel-Kompatibilität auf deutschen Systemen. + const blob = new Blob(['' + csv], { type: 'text/csv;charset=utf-8' }); + const url = URL.createObjectURL(blob); + const link = window.document.createElement('a'); + link.href = url; + link.download = filename; + window.document.body.appendChild(link); + link.click(); + window.document.body.removeChild(link); + URL.revokeObjectURL(url); +}; + +const DocumentTable = ({ + documents, + locale, + onAction, + isPending, + showAcceptedColumn, + isSelected, + onToggleSelect, + onToggleSelectAll, + allSelected, +}: { + documents: Document[]; + locale: string; + onAction: (id: string, action: TDiscoveryDocumentAction) => void; + isPending: boolean; + showAcceptedColumn: boolean; + isSelected: (id: string) => boolean; + onToggleSelect: (id: string) => void; + onToggleSelectAll: () => void; + allSelected: boolean; +}) => { + const intlDate = new Intl.DateTimeFormat(locale, { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }); + + const handleExport = () => { + const today = new Date().toISOString().slice(0, 10); + const header = [ + 'Datum', + 'Korrespondent', + 'Betreff', + 'Betrag', + 'Rechnungs-Nr', + ...(showAcceptedColumn ? ['Akzeptiert am', 'Akzeptiert von'] : []), + 'Status', + ]; + const rows = documents.map((d) => [ + d.documentDate ? intlDate.format(d.documentDate) : intlDate.format(d.capturedAt), + d.correspondent ?? '', + d.title, + d.detectedAmount ?? '', + d.detectedInvoiceNumber ?? '', + ...(showAcceptedColumn + ? [d.acceptedAt ? intlDate.format(d.acceptedAt) : '', d.acceptedByName ?? ''] + : []), + d.status, + ]); + downloadCsv(`belege-${today}.csv`, [header, ...rows]); + }; + + return ( +
+
+ +
+
+ + + + + + + + + + + + {showAcceptedColumn && ( + + )} + + + + + {documents.map((doc) => ( + + + + + + + + + + {showAcceptedColumn && ( + + )} + + + ))} + +
+ 0 && allSelected} + onCheckedChange={onToggleSelectAll} + aria-label="Alle auswählen" + /> + + Datum + + Korrespondent + + Betreff + + Betrag + + Rechnungs-Nr. + + + + Status + + Akzeptiert + + Aktion +
+ onToggleSelect(doc.id)} + aria-label={`Beleg „${doc.title}" auswählen`} + /> + + {intlDate.format(doc.documentDate ?? doc.capturedAt)} + {doc.correspondent ?? '–'} + + {doc.title} + + + {doc.detectedAmount ?? '–'} + + {doc.detectedInvoiceNumber ?? '–'} + + {doc.hasArchive && doc.attachmentCount > 0 ? ( + 1 ? '"e' : '' + } verfügbar`} + > + + {doc.attachmentCount} + + ) : ( + – + )} + + + + {statusLabel(doc.status)} + + + {doc.acceptedAt ? ( + <> + {intlDate.format(doc.acceptedAt)} + {doc.acceptedByName && ( + · {doc.acceptedByName} + )} + + ) : ( + '–' + )} + + {doc.status === 'accepted' && ( + + )} + +
+
+
+ ); +}; + +export default function FindDocumentsPage() { + const { _, i18n } = useLingui(); + const { toast } = useToast(); + const params = useParams(); + const teamUrl = params.teamUrl ?? ''; + // Default ist die Übersicht: alle Belege auf einen Blick, sortiert nach Datum. + // Workflow-Tabs (Eingang, Manuell, …) sind weiterhin erreichbar. + const [status, setStatus] = useState('all'); + const [query, setQuery] = useState(''); + const today = toDateInputValue(new Date()); + const thirtyDaysAgo = toDateInputValue(addDays(today, -30)); + const [sourceId, setSourceId] = useState(''); + const [fromDate, setFromDate] = useState(thirtyDaysAgo); + const [toDate, setToDate] = useState(today); + const [mailSearchTerm, setMailSearchTerm] = useState('Rechnung'); + // Multi-Select-State pro Tab — beim Tab-Wechsel zurueckgesetzt. + const [selectedIds, setSelectedIds] = useState>(new Set()); + + const utils = trpc.useUtils(); + + const { data, isLoading } = trpc.discovery.findDocuments.useQuery({ + status, + query: query.trim() || undefined, + }); + + useEffect(() => { + if (!sourceId && data?.sources[0]?.id) { + setSourceId(data.sources[0].id); + } + }, [data?.sources, sourceId]); + + const updateStatusMutation = trpc.discovery.updateStatus.useMutation({ + onSuccess: () => { + void utils.discovery.findDocuments.invalidate(); + }, + onError: (err) => { + toast({ + title: _(msg`Aktion fehlgeschlagen`), + description: err.message, + variant: 'destructive', + }); + }, + }); + + const startSyncRunMutation = trpc.sources.startSyncRun.useMutation({ + onSuccess: (run) => { + toast({ + title: _(msg`Postfach-Durchsuchung gestartet`), + description: _(msg`Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze.`), + }); + void utils.discovery.findDocuments.invalidate(); + void utils.sources.listSyncRuns.invalidate({ sourceId: run.sourceId, limit: 10 }); + }, + onError: (err) => { + toast({ + title: _(msg`Durchsuchung konnte nicht gestartet werden`), + description: err.message, + variant: 'destructive', + }); + }, + }); + + const handleAction = (id: string, action: TDiscoveryDocumentAction) => { + updateStatusMutation.mutate({ id, action }); + }; + + const handleStartMailboxSearch = () => { + const from = new Date(`${fromDate}T00:00:00`); + const to = addDays(toDate, 1); + + if (Number.isNaN(from.getTime()) || Number.isNaN(to.getTime()) || from >= to) { + toast({ + title: _(msg`Zeitraum prüfen`), + description: _(msg`Das Von-Datum muss vor dem Bis-Datum liegen.`), + variant: 'destructive', + }); + return; + } + + startSyncRunMutation.mutate({ + sourceId, + from, + to, + searchTerm: mailSearchTerm.trim() || undefined, + }); + }; + + const handleToggleSelect = (id: string) => { + setSelectedIds((prev) => { + const next = new Set(prev); + if (next.has(id)) next.delete(id); + else next.add(id); + return next; + }); + }; + + const handleClearSelection = () => setSelectedIds(new Set()); + + const handleStatusChange = (next: DiscoveryTab) => { + setStatus(next); + setSelectedIds(new Set()); + }; + + const hasAnySource = data?.hasAnySource ?? false; + const sources = data?.sources ?? []; + const visibleDocuments = data?.documents ?? []; + + const isSelected = (id: string) => selectedIds.has(id); + const allVisibleSelected = + visibleDocuments.length > 0 && visibleDocuments.every((d) => selectedIds.has(d.id)); + const handleToggleSelectAll = () => { + setSelectedIds((prev) => { + if (visibleDocuments.every((d) => prev.has(d.id))) { + // Alle abwählen die zur aktuellen Sicht gehören. + const next = new Set(prev); + visibleDocuments.forEach((d) => next.delete(d.id)); + return next; + } + const next = new Set(prev); + visibleDocuments.forEach((d) => next.add(d.id)); + return next; + }); + }; + + // Absoluter Pfad — relative URLs resolven hier ungewollt nach + // /t/{team}/zip-attachments (statt /t/{team}/find-documents/zip-attachments), + // weil die List-URL keinen Trailing-Slash hat. + const zipHref = `/t/${teamUrl}/find-documents/zip-attachments?ids=${Array.from(selectedIds).join(',')}`; + + return ( +
+
+

+ Dokumente finden +

+

+ + Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status + gefiltert. + +

+
+ + {hasAnySource && ( + + )} + +
+ handleStatusChange(v as DiscoveryTab)}> + + {STATUS_TABS.map((tab) => ( + + {_(tab.label)} + + ))} + + + +
+ + setQuery(e.target.value)} + /> +
+
+ +
+ {isLoading && } + + {!isLoading && data && !hasAnySource && } + + {!isLoading && data && hasAnySource && data.documents.length === 0 && ( + + )} + + {!isLoading && data && data.documents.length > 0 && ( +
+ + {selectedIds.size > 0 && ( + selectedIds.has(d.id) && d.hasArchive && d.attachmentCount > 0, + ).length + } + onClear={handleClearSelection} + zipHref={zipHref} + /> + )} + {/* "Alle" + akzeptiert + archiv ergibt typisch viele Belege — + Tabellenansicht ist da kompakter und scannbar. Eingang+Manuell + bleiben Card-Ansicht, weil dort die Action-Buttons (Akzeptieren + / Archivieren etc.) im Zentrum stehen. */} + {status === 'all' || status === 'accepted' || status === 'archived' ? ( + + ) : ( +
+ {data.documents.map((doc) => ( + + ))} +
+ )} + {data.total > data.documents.length && ( +

+ + {data.documents.length} von {data.total} angezeigt + +

+ )} +
+ )} +
+
+ ); +} diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.zip-attachments.ts b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.zip-attachments.ts new file mode 100644 index 0000000..4710a5d --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.zip-attachments.ts @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +// +// ZIP-Sammel-Download für ein oder mehrere DiscoveryDocuments. +// +// Endpoint: GET /t//find-documents/zip-attachments?ids=,,… +// Response: application/zip mit folgendem Layout: +// __/ +// mail.eml ← Original-Mail (immer) +// +// +// … +// +// Pro Document genau ein Ordner. Anhänge UND .eml gehen rein. Interne Artifacts +// (MAIL_BODY_HTML, MAIL_METADATA, MAIL_BODY_TEXT) werden bewusst NICHT gepackt — +// die sind App-intern und sollen den Beleg-Export nicht zumüllen. +// +// Sicherheits-Checks identisch zu find-documents.$id.artifacts.$artifactId.ts: +// - Session erforderlich +// - DiscoveryDocument muss zum Team gehören +// - Document.providerSource === 'local' ODER uploadedById === user.id +// - Pfad-Traversal-Schutz: Artifact-Pfade müssen unter Archive-Dir liegen +import JSZip from 'jszip'; +import { promises as fs } from 'node:fs'; +import path from 'node:path'; + +import { getSession } from '@nexasign/auth/server/lib/utils/get-session'; +import { getAbsoluteArchivePath } from '@nexasign/lib/server-only/sources/archive'; +import { getTeamByUrl } from '@nexasign/lib/server-only/team/get-team'; +import { prisma } from '@nexasign/prisma'; + +import type { Route } from './+types/find-documents.zip-attachments'; + +const MAX_DOCUMENTS_PER_ZIP = 100; +const MAX_TOTAL_BYTES = 200 * 1024 * 1024; // 200 MB Hard-Limit pro ZIP-Request + +/** + * Macht aus einem freien String einen filesystem-sicheren, kompakten Slug. + * - lower-case-conversion bleibt aus, weil Markennamen (Anthropic, NetCup) lesbar bleiben sollen + * - alle Zeichen außer ASCII-Buchstaben/Ziffern/-/_ → unterstrich + * - Mehrfach-Unterstriche → einer + * - Trim auf 60 Zeichen + */ +const slugify = (raw: string | null | undefined, fallback: string): string => { + const source = (raw ?? '').trim(); + if (source.length === 0) { + return fallback; + } + const replaced = source + .normalize('NFKD') + // Diakritika weg (ä → a, ß → ss bekommen wir hier nicht 100%, akzeptabel) + .replace(/[̀-ͯ]/g, '') + .replace(/ß/g, 'ss') + .replace(/[^A-Za-z0-9._-]+/g, '_') + .replace(/_+/g, '_') + .replace(/^[._-]+|[._-]+$/g, ''); + if (replaced.length === 0) return fallback; + return replaced.length > 60 ? replaced.slice(0, 60) : replaced; +}; + +/** + * Folder-Prefix für einen Beleg im ZIP. + * Format: YYYY-MM-DD__ + * Beispiel: 2026-03-03_Anthropic_PBC_2957-1184-4954 + * + * Sortiert sich von selbst chronologisch beim Browser-Auspacken (Datum vorn). + */ +const buildFolderName = (doc: { + documentDate: Date | null; + capturedAt: Date; + correspondent: string | null; + detectedInvoiceNumber: string | null; + title: string; + id: string; +}): string => { + const date = doc.documentDate ?? doc.capturedAt; + const dateStr = date.toISOString().slice(0, 10); // YYYY-MM-DD + const correspondent = slugify(doc.correspondent, 'Unbekannt'); + // Invoice-Nr bevorzugen — die ist eindeutiger als der Mail-Subject. + const tail = slugify(doc.detectedInvoiceNumber ?? doc.title, doc.id.slice(0, 8)); + return `${dateStr}_${correspondent}_${tail}`; +}; + +/** + * Stellt sicher, dass im ZIP keine zwei Documents im selben Ordner landen. + * Falls `buildFolderName` für zwei Belege denselben String liefert (z. B. zwei + * Mails am gleichen Tag vom gleichen Sender ohne Invoice-Nr), wird ein + * Disambig-Suffix `_2`, `_3`, … angehängt. + */ +const uniquify = (base: string, used: Set): string => { + if (!used.has(base)) { + used.add(base); + return base; + } + let i = 2; + while (used.has(`${base}_${i}`)) i += 1; + const final = `${base}_${i}`; + used.add(final); + return final; +}; + +/** + * Liest eine Datei aus dem Archive-Ordner, mit Pfad-Traversal-Schutz. + * Liefert null, wenn die Datei fehlt oder ausserhalb des Archive-Pfads liegt. + */ +const readArtifactFile = async ( + archivePath: string, + relativePath: string, +): Promise => { + const archiveDir = path.resolve(getAbsoluteArchivePath(archivePath)); + const filePath = path.resolve(archiveDir, relativePath); + const archivePrefix = `${archiveDir}${path.sep}`; + if (!filePath.startsWith(archivePrefix)) { + return null; + } + try { + return await fs.readFile(filePath); + } catch { + return null; + } +}; + +const zipFileName = (count: number): string => { + const today = new Date().toISOString().slice(0, 10); + if (count === 1) return `belege-${today}.zip`; + return `belege-${today}_${count}.zip`; +}; + +export async function loader({ request, params }: Route.LoaderArgs) { + const { user } = await getSession(request); + const team = await getTeamByUrl({ + userId: user.id, + teamUrl: params.teamUrl, + }); + + const url = new URL(request.url); + const idsRaw = url.searchParams.get('ids') ?? ''; + const ids = idsRaw + .split(',') + .map((s) => s.trim()) + .filter((s) => s.length > 0); + + if (ids.length === 0) { + throw new Response('Keine Belege ausgewählt.', { status: 400 }); + } + if (ids.length > MAX_DOCUMENTS_PER_ZIP) { + throw new Response(`Zu viele Belege auf einmal (max ${MAX_DOCUMENTS_PER_ZIP}).`, { + status: 400, + }); + } + + // Ein Query holt alle Documents — Authorization-Check inline (Team + Owner). + // Reihenfolge: documentDate aufsteigend, damit der ZIP chronologisch ist. + const documents = await prisma.discoveryDocument.findMany({ + where: { + id: { in: ids }, + teamId: team.id, + OR: [{ providerSource: 'local' }, { uploadedById: user.id }], + }, + select: { + id: true, + title: true, + correspondent: true, + documentDate: true, + capturedAt: true, + detectedInvoiceNumber: true, + archivePath: true, + artifacts: { + select: { + id: true, + kind: true, + fileName: true, + contentType: true, + fileSize: true, + relativePath: true, + }, + }, + }, + orderBy: [{ documentDate: 'asc' }, { capturedAt: 'asc' }], + }); + + if (documents.length === 0) { + throw new Response('Keine zugreifbaren Belege gefunden.', { status: 404 }); + } + + const zip = new JSZip(); + const usedFolderNames = new Set(); + let totalBytes = 0; + let documentsAdded = 0; + // Sammelt Belege ohne ladbares Archiv — landen am Ende als MANIFEST.txt + // im ZIP, damit der User sieht, was uebersprungen wurde und warum. + const skippedRecords: Array<{ + title: string; + correspondent: string | null; + documentDate: Date | null; + invoiceNumber: string | null; + reason: string; + }> = []; + + for (const doc of documents) { + if (!doc.archivePath) { + skippedRecords.push({ + title: doc.title, + correspondent: doc.correspondent, + documentDate: doc.documentDate, + invoiceNumber: doc.detectedInvoiceNumber, + reason: 'Kein Archiv vorhanden (Datensatz vor Archive-Feature importiert).', + }); + continue; + } + + const folderBase = buildFolderName({ + documentDate: doc.documentDate, + capturedAt: doc.capturedAt, + correspondent: doc.correspondent, + detectedInvoiceNumber: doc.detectedInvoiceNumber, + title: doc.title, + id: doc.id, + }); + const folderName = uniquify(folderBase, usedFolderNames); + + // Nur Anhänge + .eml in den ZIP — interne Artifacts (HTML, Body-Text, + // Metadata) bleiben App-internes Audit-Material und gehen NICHT mit. + const wanted = doc.artifacts.filter( + (art) => art.kind === 'ATTACHMENT' || art.kind === 'MAIL_EML', + ); + + let documentHadFile = false; + for (const art of wanted) { + if (totalBytes + art.fileSize > MAX_TOTAL_BYTES) { + throw new Response( + `ZIP-Größenlimit überschritten (${Math.round(MAX_TOTAL_BYTES / 1024 / 1024)} MB).`, + { status: 413 }, + ); + } + const bytes = await readArtifactFile(doc.archivePath, art.relativePath); + if (!bytes) continue; + // .eml landet als „mail.eml" im Ordner — egal wie das Original-Artefakt heisst. + const fileNameInZip = art.kind === 'MAIL_EML' ? 'mail.eml' : art.fileName; + zip.file(`${folderName}/${fileNameInZip}`, bytes); + totalBytes += bytes.length; + documentHadFile = true; + } + + if (documentHadFile) { + documentsAdded += 1; + } else { + // archivePath gesetzt, aber Files fehlen physisch (Disk-Loss?). + skippedRecords.push({ + title: doc.title, + correspondent: doc.correspondent, + documentDate: doc.documentDate, + invoiceNumber: doc.detectedInvoiceNumber, + reason: `archivePath gesetzt, aber keine Datei lesbar unter ${doc.archivePath}.`, + }); + } + } + + // Manifest mitliefern, wenn überhaupt was uebersprungen wurde — egal ob + // alles oder nur ein Teil. So bekommt der User ein vollstaendiges Bild. + if (skippedRecords.length > 0) { + const today = new Date().toISOString().slice(0, 10); + const lines = [ + `NexaFile — ZIP-Export ${today}`, + `Belege ausgewaehlt: ${documents.length}`, + `Belege im ZIP enthalten: ${documentsAdded}`, + `Belege uebersprungen: ${skippedRecords.length}`, + '', + '── Uebersprungen ─────────────────────────────────────────────', + '', + ]; + for (const r of skippedRecords) { + const date = r.documentDate ? r.documentDate.toISOString().slice(0, 10) : '????-??-??'; + const corresp = r.correspondent ?? 'Unbekannt'; + const invNo = r.invoiceNumber ? `, Rechnungs-Nr ${r.invoiceNumber}` : ''; + lines.push(`${date} ${corresp}${invNo}`); + lines.push(` Subject: ${r.title}`); + lines.push(` Grund: ${r.reason}`); + lines.push(''); + } + zip.file('MANIFEST.txt', lines.join('\n')); + } + + if (documentsAdded === 0 && skippedRecords.length === 0) { + // Sollte nicht passieren — defensives Fallback. + throw new Response('Keine zugreifbaren Belege gefunden.', { status: 404 }); + } + + // STORE = keine Komprimierung. PDFs/Images sind bereits komprimiert, + // DEFLATE bringt kaum etwas und kostet CPU+Latenz im Request-Handler. + const buffer = await zip.generateAsync({ + type: 'nodebuffer', + compression: 'STORE', + }); + + return new Response(buffer, { + headers: { + 'Content-Type': 'application/zip', + 'Content-Length': String(buffer.length), + 'Content-Disposition': `attachment; filename="${zipFileName(documentsAdded)}"`, + 'Cache-Control': 'private, no-store', + 'X-Content-Type-Options': 'nosniff', + }, + }); +} diff --git a/apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx b/apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx new file mode 100644 index 0000000..1e33892 --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx @@ -0,0 +1,177 @@ +import { msg } from '@lingui/core/macro'; +import { Trans } from '@lingui/react/macro'; + +import { appMetaTags } from '~/utils/meta'; + +/** + * Vorlagen-Übersicht — vormals PHP unter templates/vorlagen-index/index.php. + * Migration zu Remix-Route, damit /vorlagen/ dieselbe App-Header-Navigation + * nutzt wie /find-documents, /documents, /inbox etc. Eine Codebase, eine Nav. + * + * Die einzelnen Generator-Seiten (/vorlagen/av-vertrag/, /vorlagen/x-rechnung/, …) + * bleiben PHP-FPM-Routes — die enthalten tiefe PDF/ZUGFeRD-Pipeline-Logik, die + * nicht trivial in Remix portierbar ist. Klick auf eine Karte hier verlinkt + * weiterhin auf die PHP-Seite, ist also harter Page-Reload. + */ + +type VorlagenItem = { + slug: string; + badge: string; + titel: string; + desc: string; + href: string; + cta: string; +}; + +const VORLAGEN: VorlagenItem[] = [ + { + slug: 'av-vertrag', + badge: 'Generator', + titel: 'AV-Vertrag nach Art. 28 DSGVO', + desc: 'Auftragsverarbeitungs-Vertrag für jedes B2B-SaaS. 14 Felder ausfüllen, fertig unterschriftsreifes PDF mit TOM-Anhang und Unterauftragsverarbeiter-Liste.', + href: '/vorlagen/av-vertrag/', + cta: 'Generator starten', + }, + { + slug: 'x-rechnung', + badge: 'Generator', + titel: 'X-Rechnung / ZUGFeRD-Generator', + desc: 'E-Rechnungspflicht ab 2025: Ihr Rechnungs-PDF + Strukturdaten → PDF/A-3 mit eingebettetem EN 16931 XML (ZUGFeRD Comfort). B2B-pflichtkonform im Empfang beim Kunden.', + href: '/vorlagen/x-rechnung/', + cta: 'Generator starten', + }, + { + slug: 'nda-einseitig', + badge: 'Generator', + titel: 'NDA — einseitig', + desc: 'Vertraulichkeitsvereinbarung, wenn nur eine Partei offenlegt (Bewerbungen, Partnergespräche).', + href: '/vorlagen/nda-einseitig/', + cta: 'Generator starten', + }, + { + slug: 'nda-gegenseitig', + badge: 'Generator', + titel: 'NDA — gegenseitig', + desc: 'Wechselseitige Vertraulichkeit für echte B2B-Verhandlungen.', + href: '/vorlagen/nda-gegenseitig/', + cta: 'Generator starten', + }, + { + slug: 'freelancer-werkvertrag', + badge: 'Generator', + titel: 'Freelancer- / Werkvertrag', + desc: 'Projektarbeit mit freien Mitarbeitenden — inkl. Nutzungsrechte und Abnahme.', + href: '/vorlagen/freelancer-werkvertrag/', + cta: 'Generator starten', + }, + { + slug: 'arbeitsvertrag-unbefristet', + badge: 'Generator', + titel: 'Arbeitsvertrag — unbefristet', + desc: 'Festanstellung nach deutschem Arbeitsrecht. Nachweisgesetz-konform.', + href: '/vorlagen/arbeitsvertrag-unbefristet/', + cta: 'Generator starten', + }, + { + slug: 'arbeitsvertrag-befristet', + badge: 'Generator', + titel: 'Arbeitsvertrag — befristet', + desc: 'Befristung nach TzBfG, mit oder ohne Sachgrund.', + href: '/vorlagen/arbeitsvertrag-befristet/', + cta: 'Generator starten', + }, + { + slug: 'beratungsvertrag', + badge: 'Generator', + titel: 'Beratungsvertrag', + desc: 'Consulting, Coaching, Strategieberatung — inkl. Vergütung und Vertraulichkeit.', + href: '/vorlagen/beratungsvertrag/', + cta: 'Generator starten', + }, + { + slug: 'aufhebungsvertrag', + badge: 'Generator', + titel: 'Aufhebungsvertrag', + desc: 'Einvernehmliche Beendigung eines Arbeitsverhältnisses inkl. Abfindungs-Platzhalter.', + href: '/vorlagen/aufhebungsvertrag/', + cta: 'Generator starten', + }, + { + slug: 'angebotsannahme', + badge: 'Generator', + titel: 'Angebotsannahme / Auftragsbestätigung', + desc: 'Standard-Geschäftsabschluss nach BGB-Angebotsannahme.', + href: '/vorlagen/angebotsannahme/', + cta: 'Generator starten', + }, + { + slug: 'agb-zustimmung', + badge: 'Generator', + titel: 'AGB-Zustimmung', + desc: 'Für Online-Registrierung oder Software-Rollout im Unternehmen.', + href: '/vorlagen/agb-zustimmung/', + cta: 'Generator starten', + }, +]; + +export function meta() { + return appMetaTags(msg`Vorlagen`); +} + +export default function VorlagenIndex() { + return ( +
+

+ Vertragsvorlagen für deutsche Unternehmen +

+

+ + 11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage + als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und + signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt. + +

+ + + +
+ ⚖️ Rechtlicher Hinweis +
+ + Diese Vorlagen dienen zur Orientierung und stellen keine Rechtsberatung + i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch + zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes + Risiko. + +
+
+ + Quelle: NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und + Pull Requests willkommen. + +
+
+ ); +} diff --git a/apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx b/apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx new file mode 100644 index 0000000..05a35ac --- /dev/null +++ b/apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx @@ -0,0 +1,472 @@ +import { msg } from '@lingui/core/macro'; +import { Trans } from '@lingui/react/macro'; + +import { appMetaTags } from '~/utils/meta'; + +/** + * GoBD-Hub — vormals PHP unter templates/vorlagen-index/gobd/index.php. + * Migration zu Remix-Route, damit /vorlagen/gobd/ dieselbe App-Header-Navigation + * nutzt wie der Rest der App. Eine Codebase, eine Nav. + */ + +export function meta() { + return appMetaTags(msg`GoBD-Archivierung`); +} + +type Module = { + badge: string; + badgeColor?: 'primary' | 'warning'; + href?: string; + titel: string; + desc: string; + cta: string; + disabled?: boolean; +}; + +const MODULES: Module[] = [ + { + badge: 'Wissen', + href: '#was-ist-gobd', + titel: 'Was ist GoBD?', + desc: 'Einstieg für Nicht-Fachleute — was bedeutet GoBD, wen betrifft es, welche Fristen gelten.', + cta: 'Zum Abschnitt', + }, + { + badge: 'Verantwortung', + href: '#verantwortung', + titel: 'NexaFile vs. Sie', + desc: 'Klare Aufteilung: was deckt NexaFile technisch ab, was müssen Sie organisatorisch selbst regeln.', + cta: 'Verantwortungs-Split', + }, + { + badge: 'Download', + href: '/vorlagen/download/11-verfahrensdokumentation-gobd.md', + titel: 'Verfahrensdokumentation', + desc: 'GoBD-Pflichtdokument. Vorlage mit Platzhaltern — Steuerberater gegenprüfen lassen, dann ablegen.', + cta: 'Vorlage laden', + }, + { + badge: 'Tool', + href: '#export-tool', + titel: 'Export-CLI', + desc: 'Exportiert signierte Dokumente, akzeptierte gefundene Belege, Mail-Artefakte und Audit-Logs als ZIP-Paket.', + cta: 'Nutzung', + }, + { + badge: 'Prüfung', + href: '#zugriffsarten', + titel: 'Finanzamt-Zugriffsarten', + desc: 'Z1, Z2, Z3 — was bedeuten die Zugriffs-Szenarien und was liefert NexaFile dafür.', + cta: 'Erklärung', + }, + { + badge: 'Schutz', + href: '#retention', + titel: 'WORM-Enforcement in der App', + desc: 'Akzeptierte gefundene Belege und abgeschlossene Signaturdokumente sind vor versehentlichem Löschen geschützt.', + cta: 'Schutzlogik', + }, + { + badge: 'Tool', + href: '#retention', + titel: 'Retention-Cron (10 Jahre)', + desc: 'Automatische Fristenkontrolle: keine Dokumente vor Ablauf der 10-Jahres-Pflicht löschen.', + cta: 'Fristenkontrolle', + }, + { + badge: 'Prüfung', + href: '#export-tool', + titel: 'SHA-256-Manifest', + desc: 'Integritätsnachweis für jeden Export: unveränderte Hashes der Originale.', + cta: 'Im Export enthalten', + }, +]; + +const FAQ: { q: string; a: React.ReactNode }[] = [ + { + q: 'Was ist WORM?', + a: ( +

+ „Write Once Read Many" — Einmal geschriebene Dokumente können gelesen, aber + nicht mehr geändert oder gelöscht werden (innerhalb der Aufbewahrungsfrist). Das ist das + technische Fundament für Unveränderbarkeit nach § 146 Abs. 4 AO. +

+ ), + }, + { + q: 'Was ist ein SHA-256-Hash?', + a: ( +

+ Ein digitaler Fingerabdruck eines Dokuments — eine 64-stellige hexadezimale + Zeichenkette, die eindeutig ist. Ändert sich auch nur ein Byte am Dokument, passt der Hash + nicht mehr. Damit wird Unverändertheit mathematisch nachweisbar. +

+ ), + }, + { + q: 'Was ist ein Audit-Log?', + a: ( +

+ Ein Protokoll aller Ereignisse eines Dokuments: wer hat es erstellt, wer geöffnet, wer + signiert, wann heruntergeladen. Append-Only heißt: Einträge können nur hinzugefügt + werden, nicht gelöscht oder verändert. +

+ ), + }, + { + q: 'Was bedeutet IDW PS 880 / IDW 951?', + a: ( +

+ Prüfungsstandards des Instituts der Wirtschaftsprüfer für IT-Systeme (PS + 880) bzw. Dienstleister (PS 951). Darauf basieren formale „revisionssicher"-Testate. Eine + solche Prüfung kostet typischerweise einen fünfstelligen Betrag und ist nur dann sinnvoll, + wenn Sie das Testat gegenüber Kunden oder Aufsichtsbehörden formal nachweisen müssen. +

+ ), + }, + { + q: 'Muss ich den Steuerberater einbeziehen?', + a: ( +

+ Ja — spätestens bei der Verfahrensdokumentation und der jährlichen + Integritätskontrolle. Die GoBD sind steuerliches Recht, und ein formal sauberes Setup ist + Aufgabe von Buchhaltung und Steuerberatung. NexaFile liefert die Technik, Sie liefern die + Prozess-Freigaben. +

+ ), + }, + { + q: 'Darf NexaFile selbst sich „GoBD-konform" nennen?', + a: ( +

+ Nein. NexaFile ist „GoBD-ready": die technischen Funktionen sind da. + „GoBD-konform" im juristischen Sinn wird erst Ihre konkrete Implementierung (Technik + + Organisation + Verfahrensdokumentation). Für ein formales Testat wäre ein Wirtschaftsprüfer + einzubeziehen. +

+ ), + }, +]; + +export default function GoBDPage() { + return ( +
+

+ GoBD-konforme Archivierung mit NexaFile +

+

+ + Unterschriebene Verträge sind steuerrelevante Belege — das Finanzamt darf + sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine{' '} + GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, + FAQ. + +

+ + {/* Module */} +

+ Bausteine +

+
+ {MODULES.map((m) => { + const cls = m.disabled + ? 'flex flex-col gap-2 rounded-xl border-[1.5px] border-border bg-card p-6 opacity-55' + : 'group flex flex-col gap-2 rounded-xl border-[1.5px] border-border bg-card p-6 no-underline transition hover:-translate-y-0.5 hover:border-primary hover:shadow-md'; + const badgeCls = + m.badgeColor === 'warning' + ? 'self-start rounded-full bg-amber-100 px-2 py-0.5 text-[0.7rem] font-bold uppercase tracking-wider text-amber-700' + : 'self-start rounded-full bg-primary/10 px-2 py-0.5 text-[0.7rem] font-bold uppercase tracking-wider text-primary'; + + const inner = ( + <> + {m.badge} +

+ {m.titel} +

+
+ {m.desc} +
+
+ {m.cta} + {!m.disabled && →} +
+ + ); + + if (m.disabled) { + return ( +
+ {inner} +
+ ); + } + return ( + + {inner} + + ); + })} +
+ + {/* Was ist GoBD */} +

+ Was ist GoBD überhaupt? +

+

+ + GoBD steht für{' '} + + „Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und + Unterlagen in elektronischer Form sowie zum Datenzugriff" + {' '} + — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, + die Bücher führen. + +

+

+ + Kern: Wenn Sie steuerrelevante Dokumente (Rechnungen, Verträge, + Handelsbriefe) digital erzeugen oder ablegen, müssen sie{' '} + 10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt + zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter + diese Pflicht. + +

+ + {/* Verantwortung */} +

+ Die Verantwortungs-Teilung +

+

+ + GoBD-Konformität ist nie die Leistung eines einzelnen Tools. Sie entsteht + aus dem Zusammenspiel von drei Elementen: + +

+
+
+

+ ✅ Was NexaFile liefert +

+
    +
  • + Unveränderbare Ablage signierter PDFs mit kryptografischem Hash +
  • +
  • + Server-Archiv für gefundene Belege mit Original-Mail, Body, Metadaten + und Anhängen +
  • +
  • + Append-Only Audit-Log — wer, was, wann, bei welchem Envelope +
  • +
  • + Export-CLI nexasign-gobd-export für Z2/Z3-Prüfzugriff +
  • +
  • + Verfahrensdokumentations-Vorlage zum Anpassen und Freigeben +
  • +
  • + Rollen-/Rechte-Management (z. B. Nur-Lese-Konto für Steuerberater) +
  • +
  • + TLS + DB-Verschlüsselung im Ruhezustand +
  • +
+
+
+

+ 👤 Was Sie selbst regeln +

+
    +
  • + Verfahrensdokumentation schreiben, pflegen, freigeben lassen +
  • +
  • + Datensicherung (Backups, Off-Site-Kopien, Wiederherstellungstests) +
  • +
  • + Zugriffsrechte sauber nach Need-to-know vergeben +
  • +
  • + Personalwechsel-Prozesse (Handover, Rechte-Entzug) +
  • +
  • + Jährliche Integritätskontrollen (Hash-Vergleich, Test-Export) +
  • +
  • + Optional: Wirtschaftsprüfer-Testat nach IDW PS 880 / IDW 951 +
  • +
+
+
+ + {/* Zugriffsarten */} +

+ Finanzamt-Zugriff: Z1, Z2, Z3 +

+

+ Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern: +

+
    +
  • + Z1 — unmittelbarer Zugriff: Der/Die Prüfer/in loggt sich mit einem + Nur-Lese-Konto direkt in die NexaFile-Instanz ein und sichtet Dokumente online. +
  • +
  • + Z2 — mittelbarer Zugriff: Sie exportieren die angeforderten Dokumente in + einem strukturierten Format; der/die Prüfer/in bekommt das Ergebnis. +
  • +
  • + Z3 — Datenträgerüberlassung: Das Export-Paket wird auf einem + verschlüsselten USB-Medium übergeben. +
  • +
+

+ + Für Z2 und Z3 liefert NexaFile das CLI-Tool{' '} + nexasign-gobd-export — siehe nächster Abschnitt. + +

+ + {/* Export-Tool */} +

+ Export-CLI — + nexasign-gobd-export +

+

+ + Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten + Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines + Zeitraums als strukturiertes Paket. + +

+

+ Nutzung +

+
+        {`sudo nexasign-gobd-export   
+
+# Beispiel — kompletter Zeitraum 2026:
+sudo nexasign-gobd-export 2026-01-01 2026-12-31 /tmp/gobd-2026`}
+      
+

+ Inhalt des Export-Pakets +

+
    +
  • + envelopes.csv — Metadaten aller signierten Envelopes (ID, Titel, Status, + Zeitstempel) +
  • +
  • + audit-log.csv — Vollständiger Audit-Trail im Zeitraum +
  • +
  • + discovery-documents.csv — akzeptierte gefundene Belege nach{' '} + acceptedAt +
  • +
  • + discovery-audit-log.csv — Audit-Trail der Quellen- und Belegsuche +
  • +
  • + discovery-missing-artifacts.csv — Prüfliste akzeptierter Belege, bei denen + Mail- oder Anhang-Dateien nachgeladen werden müssen +
  • +
  • + documents/<envelope-id>/... — signierte PDF-Dateien +
  • +
  • + discovery/<discovery-document-id>/... — gespeicherte E-Mails, + Body-Dateien, Metadaten und Anhänge +
  • +
  • + manifest.sha256 — SHA-256-Hashes aller enthaltenen Dateien +
  • +
  • + README.md — Beschreibung des Pakets und rechtlicher Kontext +
  • +
  • + nexasign-gobd-export_VON_BIS.zip — alles zusammengefasst +
  • +
+

+ + Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die + Mail-Artefakte werden vom Host-Pfad NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; + Standard ist /var/lib/nexasign-archive. + +

+ + {/* Retention */} +

+ Retention-Check und Löschschutz +

+

+ + Für signierte Dokumente startet die Aufbewahrung mit completedAt. Für + gefundene Belege startet sie mit acceptedAt, also in dem Moment, in dem Sie + den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die + 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch. + +

+
+        {`sudo nexasign-retention-check`}
+      
+ + {/* FAQ */} +

+ Fachbegriffe & FAQ +

+
+ {FAQ.map((f) => ( +
+ + {f.q} + +
{f.a}
+
+ ))} +
+ + {/* Legal */} +
+ ⚖️ Rechtlicher Hinweis +
+ + NexaFile stellt GoBD-orientierte Archivfunktionen zur Verfügung. Die + GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in + Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt + keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit + Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit + einer/m Wirtschaftsprüfer/in. + +
+
+ + NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung. + +
+
+ ); +} diff --git a/apps/remix/app/routes/_profile+/_layout.tsx b/apps/remix/app/routes/_profile+/_layout.tsx index f174f24..2d4d427 100644 --- a/apps/remix/app/routes/_profile+/_layout.tsx +++ b/apps/remix/app/routes/_profile+/_layout.tsx @@ -57,7 +57,7 @@ export default function PublicProfileLayout() { NexaSign Logo - While waiting for them to do so you can create your own NexaSign account and get + While waiting for them to do so you can create your own NexaFile account and get started with document signing right away. diff --git a/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx b/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx index 4c5cccf..a961adf 100644 --- a/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx +++ b/apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx @@ -381,7 +381,7 @@ const SigningPageV1 = ({ data }: { data: Awaited Want to send slick signing links like this one?{' '} - Check out NexaSign + Check out NexaFile .
@@ -478,7 +478,7 @@ const SigningPageV2 = ({ data }: { data: Awaited Want to send slick signing links like this one?{' '} - Check out NexaSign + Check out NexaFile . diff --git a/apps/remix/app/routes/_share+/share.$slug.opengraph.tsx b/apps/remix/app/routes/_share+/share.$slug.opengraph.tsx index 04f7584..2ff5273 100644 --- a/apps/remix/app/routes/_share+/share.$slug.opengraph.tsx +++ b/apps/remix/app/routes/_share+/share.$slug.opengraph.tsx @@ -41,7 +41,7 @@ export const loader = async ({ params }: Route.LoaderArgs) => { ), ]); - // NexaSign-Wortmarke: Satori fetcht das Image selbst, solange die URL absolut ist. + // NexaFile-Wortmarke: Satori fetcht das Image selbst, solange die URL absolut ist. // 2x-Variante für scharfes Rendering auf der 1200×630-Card. const logoUrl = `${baseUrl}/logo-2x.png`; @@ -82,9 +82,8 @@ export const loader = async ({ params }: Route.LoaderArgs) => { position: 'relative', }} > - {/* Das Upstream-Bild og-share-frame2.png enthält ein „NexaSign"-Wasserzeichen - und „Join NexaSign" oben rechts — für NexaSign passt das nicht. Wir rendern - stattdessen einen neutralen Rahmen + dezenten NexaSign-Hinweis unten rechts. */} + {/* Das Upstream-Bild og-share-frame2.png enthält ein altes Wasserzeichen. + Wir rendern stattdessen einen neutralen Rahmen + dezenten NexaFile-Hinweis unten rechts. */}
{ /> NexaSign return {}; } - // Is hardcoded because this whole meta is hardcoded anyway for NexaSign. + // Is hardcoded because this whole meta is hardcoded anyway for NexaFile. throw redirect('/'); }; diff --git a/apps/remix/app/routes/_unauthenticated+/_layout.tsx b/apps/remix/app/routes/_unauthenticated+/_layout.tsx index 7664f58..7fdf65a 100644 --- a/apps/remix/app/routes/_unauthenticated+/_layout.tsx +++ b/apps/remix/app/routes/_unauthenticated+/_layout.tsx @@ -18,22 +18,22 @@ export default function Layout() { />
- {/* NexaSign-Wortmarke über dem Login-Formular — gibt allen öffentlichen + {/* NexaFile-Wortmarke über dem Login-Formular — gibt allen öffentlichen Seiten (Signin, Signup, Forgot-Password, …) einen sichtbaren Brand-Anker. */} NexaSign diff --git a/apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx b/apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx index 08b7848..5b7452f 100644 --- a/apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx +++ b/apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx @@ -17,7 +17,7 @@ export default function SignatureDisclosure() {

- Thank you for using NexaSign to perform your electronic document signing. The purpose of + Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below. @@ -135,7 +135,7 @@ export default function SignatureDisclosure() {

- By proceeding to use the electronic signature service provided by NexaSign, you affirm + By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein. diff --git a/apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx b/apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx index ae2c5ea..440da36 100644 --- a/apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx +++ b/apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx @@ -209,7 +209,7 @@ export default function OrganisationSignIn({ loaderData }: Route.ComponentProps)

- Return to NexaSign sign in page here + Return to NexaFile sign in page here
diff --git a/apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx b/apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx index a8d9e36..ab0c666 100644 --- a/apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx +++ b/apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx @@ -147,7 +147,7 @@ export default function VerifyEmailPage({ loaderData }: Route.ComponentProps) {

Your email has been successfully confirmed! You can now use all features of - NexaSign. + NexaFile.

@@ -174,7 +174,7 @@ export default function VerifyEmailPage({ loaderData }: Route.ComponentProps) {

- Your email has already been confirmed. You can now use all features of NexaSign. + Your email has already been confirmed. You can now use all features of NexaFile.

diff --git a/apps/remix/app/utils/meta.ts b/apps/remix/app/utils/meta.ts index f127d9e..2ecda2d 100644 --- a/apps/remix/app/utils/meta.ts +++ b/apps/remix/app/utils/meta.ts @@ -4,11 +4,11 @@ import { NEXT_PUBLIC_WEBAPP_URL } from '@nexasign/lib/constants/app'; export const appMetaTags = (title?: MessageDescriptor) => { const description = - 'NexaSign ist die deutsche, selbstgehostete Alternative für digitale Signaturen. Open Source, DSGVO-konform und in Deutschland betreibbar. Unterschreiben Sie Verträge in Ihrer eigenen Infrastruktur, ohne Abo und ohne Drittpartei-Server.'; + 'NexaFile ist die deutsche, selbstgehostete Open-Source-Plattform für Dokumente: erstellen, finden, signieren und GoBD-orientiert archivieren.'; return [ { - title: title ? `${i18n._(title)} – NexaSign` : 'NexaSign – Dokumente digital unterzeichnen', + title: title ? `${i18n._(title)} – NexaFile` : 'NexaFile – Dokumente im eigenen Stack', }, { name: 'description', @@ -17,7 +17,7 @@ export const appMetaTags = (title?: MessageDescriptor) => { { name: 'keywords', content: - 'NexaSign, NexaStack, digitale Signatur, elektronische Unterschrift, Open Source, DSGVO, Self-Hosted, Deutschland', + 'NexaFile, NexaStack, Dokumentenmanagement, digitale Signatur, elektronische Unterschrift, GoBD, Open Source, DSGVO, Self-Hosted, Deutschland', }, { name: 'author', @@ -29,7 +29,7 @@ export const appMetaTags = (title?: MessageDescriptor) => { }, { property: 'og:title', - content: 'NexaSign – die deutsche DocuSign-Alternative, selbstgehostet', + content: 'NexaFile – Dokumente erstellen, finden, signieren und archivieren', }, { property: 'og:description', diff --git a/apps/remix/app/utils/redirect-to-preferred-team.server.ts b/apps/remix/app/utils/redirect-to-preferred-team.server.ts new file mode 100644 index 0000000..2bc5407 --- /dev/null +++ b/apps/remix/app/utils/redirect-to-preferred-team.server.ts @@ -0,0 +1,28 @@ +import { redirect } from 'react-router'; + +import { extractCookieFromHeaders } from '@nexasign/auth/server/lib/utils/cookies'; +import { getOptionalSession } from '@nexasign/auth/server/lib/utils/get-session'; +import { getTeams } from '@nexasign/lib/server-only/team/get-teams'; +import { ZTeamUrlSchema } from '@nexasign/trpc/server/team-router/schema'; + +export const getPreferredTeamUrlOrRedirect = async (request: Request): Promise => { + const session = await getOptionalSession(request); + + if (!session.isAuthenticated || !session.user) { + throw redirect('/signin'); + } + + const teamUrlCookie = extractCookieFromHeaders('preferred-team-url', request.headers); + const preferredTeamUrl = + teamUrlCookie && ZTeamUrlSchema.safeParse(teamUrlCookie).success ? teamUrlCookie : undefined; + + const teams = await getTeams({ userId: session.user.id }); + const currentTeam = + teams.find((team) => team.url === preferredTeamUrl) ?? (teams.length === 1 ? teams[0] : null); + + if (!currentTeam) { + throw redirect('/inbox'); + } + + return currentTeam.url; +}; diff --git a/apps/remix/package.json b/apps/remix/package.json index 5deb8b7..53c7859 100644 --- a/apps/remix/package.json +++ b/apps/remix/package.json @@ -17,6 +17,7 @@ "@cantoo/pdf-lib": "^2.5.3", "@nexasign/api": "*", "@nexasign/assets": "*", + "jszip": "^3.10.1", "@nexasign/auth": "*", "@nexasign/ee": "*", "@nexasign/lib": "*", diff --git a/apps/remix/public/android-chrome-192x192.png b/apps/remix/public/android-chrome-192x192.png index 7613afd..6a87ffe 100644 Binary files a/apps/remix/public/android-chrome-192x192.png and b/apps/remix/public/android-chrome-192x192.png differ diff --git a/apps/remix/public/android-chrome-512x512.png b/apps/remix/public/android-chrome-512x512.png index 9d6675a..f0ae06b 100644 Binary files a/apps/remix/public/android-chrome-512x512.png and b/apps/remix/public/android-chrome-512x512.png differ diff --git a/apps/remix/public/apple-touch-icon.png b/apps/remix/public/apple-touch-icon.png index 22b756a..397584b 100644 Binary files a/apps/remix/public/apple-touch-icon.png and b/apps/remix/public/apple-touch-icon.png differ diff --git a/apps/remix/public/favicon-16x16.png b/apps/remix/public/favicon-16x16.png index ddb28ae..2c173c9 100644 Binary files a/apps/remix/public/favicon-16x16.png and b/apps/remix/public/favicon-16x16.png differ diff --git a/apps/remix/public/favicon-32x32.png b/apps/remix/public/favicon-32x32.png index 210dcb4..cdc17f6 100644 Binary files a/apps/remix/public/favicon-32x32.png and b/apps/remix/public/favicon-32x32.png differ diff --git a/apps/remix/public/favicon.ico b/apps/remix/public/favicon.ico index b295574..9749fc5 100644 Binary files a/apps/remix/public/favicon.ico and b/apps/remix/public/favicon.ico differ diff --git a/apps/remix/public/logo-1x.png b/apps/remix/public/logo-1x.png index 1bf35c2..8bb042d 100644 Binary files a/apps/remix/public/logo-1x.png and b/apps/remix/public/logo-1x.png differ diff --git a/apps/remix/public/logo-1x.webp b/apps/remix/public/logo-1x.webp index 1967a96..16fff27 100644 Binary files a/apps/remix/public/logo-1x.webp and b/apps/remix/public/logo-1x.webp differ diff --git a/apps/remix/public/logo-2x.png b/apps/remix/public/logo-2x.png index 3c88adc..b5214e4 100644 Binary files a/apps/remix/public/logo-2x.png and b/apps/remix/public/logo-2x.png differ diff --git a/apps/remix/public/logo-2x.webp b/apps/remix/public/logo-2x.webp index 65fe2c1..295600d 100644 Binary files a/apps/remix/public/logo-2x.webp and b/apps/remix/public/logo-2x.webp differ diff --git a/apps/remix/public/static/logo.png b/apps/remix/public/static/logo.png index 4813aaa..49f53e2 100644 Binary files a/apps/remix/public/static/logo.png and b/apps/remix/public/static/logo.png differ diff --git a/apps/remix/server/redirects.ts b/apps/remix/server/redirects.ts index 2c971d7..910dc1b 100644 --- a/apps/remix/server/redirects.ts +++ b/apps/remix/server/redirects.ts @@ -6,12 +6,7 @@ export const handleRedirects = async (c: Context): Promise => { const path = req.path; // Direct rewrites - if ( - path === '/documents' || - path === '/documents/folders' || - path === '/templates' || - path === '/templates/folders' - ) { + if (path === '/documents/folders' || path === '/templates' || path === '/templates/folders') { return '/'; } diff --git a/deploy/nginx/nexasign.nexastack.co.conf b/deploy/nginx/nexasign.nexastack.co.conf new file mode 100644 index 0000000..e38b539 --- /dev/null +++ b/deploy/nginx/nexasign.nexastack.co.conf @@ -0,0 +1,152 @@ +server { + server_name nexasign.nexastack.co; + + client_max_body_size 64M; + + # ACME-Challenge für Let's Encrypt — unverschlüsselt erreichbar + location /.well-known/acme-challenge/ { + root /var/www/html; + try_files $uri =404; + } + + # Alle anderen Requests an die App weiterreichen (später certbot auf 443 umstellen) + + # /vorlagen/ und /vorlagen/gobd/ sind seit 2026-04-30 Remix-Routes, + # implementiert in apps/remix/app/routes/_authenticated+/vorlagen+/ — + # damit es nur EINE Navigation gibt (nicht zwei: PHP-_nav.php + Remix-AppHeader). + # Die Generator-Seiten (/vorlagen//, av-vertrag, x-rechnung, …) bleiben + # PHP-FPM, weil deren PDF-/ZUGFeRD-Pipeline tief in PHP-Composer-Welt sitzt. + # Die Uebersicht und GoBD-Hub fallen durch zu `location /` (Remix proxy_pass). + + # Markdown-Download: /vorlagen/download/.md → download.php + location ~ ^/vorlagen/download/([0-9a-z][0-9a-z-]*\.md)$ { + include snippets/nexasign-php-headers.conf; + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME /var/www/nexasign/vorlagen/download.php; + fastcgi_param QUERY_STRING file=$1; + } + # Source-MD-Verzeichnis nie direkt ausliefern + location ^~ /vorlagen/source-md/ { return 404; } + # Generische Vertragsgeneratoren aus Markdown-Vorlagen + location ~ ^/vorlagen/(nda-einseitig|nda-gegenseitig|freelancer-werkvertrag|arbeitsvertrag-unbefristet|arbeitsvertrag-befristet|beratungsvertrag|aufhebungsvertrag|angebotsannahme|agb-zustimmung)$ { + return 301 /vorlagen/$1/; + } + location ~ ^/vorlagen/(nda-einseitig|nda-gegenseitig|freelancer-werkvertrag|arbeitsvertrag-unbefristet|arbeitsvertrag-befristet|beratungsvertrag|aufhebungsvertrag|angebotsannahme|agb-zustimmung)/$ { + include snippets/nexasign-php-headers.conf; + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME /var/www/nexasign/vorlagen/generator.php; + fastcgi_param QUERY_STRING slug=$1; + fastcgi_read_timeout 90s; + } + + # /vorlagen/gobd/ ist Remix-Route — siehe Hinweis am Anfang des Server-Blocks. + + # Statische Vorlagen-Seiten (PHP, nicht Docker) — expliziter Exact-Match pro Vorlage + location = /vorlagen/av-vertrag { + return 301 /vorlagen/av-vertrag/; + } + location = /vorlagen/av-vertrag/ { + limit_req zone=nexasign_pdf burst=3 nodelay; + include snippets/nexasign-php-headers.conf; + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME /var/www/nexasign/vorlagen/av-vertrag/index.php; + fastcgi_read_timeout 90s; + } + # Falls direkt .php ueber URL aufgerufen: gleiches Handling + location ~ ^/vorlagen/av-vertrag/index\.php$ { + include snippets/nexasign-php-headers.conf; + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME /var/www/nexasign/vorlagen/av-vertrag/index.php; + fastcgi_read_timeout 90s; + } + # Zugriff auf Template-Include blocken + location = /vorlagen/av-vertrag/template.html.php { return 404; } + + # ───── X-Rechnung / ZUGFeRD-Generator ───── + location = /vorlagen/x-rechnung { + return 301 /vorlagen/x-rechnung/; + } + location = /vorlagen/x-rechnung/ { + client_max_body_size 15m; + include snippets/nexasign-php-headers.conf; + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME /var/www/nexasign/vorlagen/x-rechnung/index.php; + fastcgi_read_timeout 120s; + } + location = /vorlagen/x-rechnung/extract { + client_max_body_size 15m; + limit_req zone=nexasign_extract burst=5 nodelay; + include snippets/nexasign-php-headers.conf; + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME /var/www/nexasign/vorlagen/x-rechnung/extract.php; + fastcgi_read_timeout 60s; + } + location = /vorlagen/x-rechnung/generate { + client_max_body_size 15m; + limit_req zone=nexasign_pdf burst=3 nodelay; + include snippets/nexasign-php-headers.conf; + include fastcgi_params; + fastcgi_pass unix:/run/php/php8.4-fpm.sock; + fastcgi_param SCRIPT_FILENAME /var/www/nexasign/vorlagen/x-rechnung/generate.php; + fastcgi_read_timeout 120s; + } + # Composer / vendor / interne Dateien nicht ausliefern + location ^~ /vorlagen/x-rechnung/vendor/ { return 404; } + location = /vorlagen/x-rechnung/composer.json { return 404; } + location = /vorlagen/x-rechnung/composer.lock { return 404; } + location = /vorlagen/x-rechnung/composer { return 404; } + + + # NexaSign-Logo — statisch direkt aus /var/www/nexasign/ ausliefern, + # damit sowohl die PHP-Vorlagen-Seiten als auch die Remix-App dasselbe + # Asset nutzen und kein Docker-Rebuild für Logo-Updates nötig ist. + location ~* ^/logo-(1x|2x)\.(webp|png)$ { + root /var/www/nexasign; + expires 30d; + add_header Cache-Control "public, immutable"; + access_log off; + } + + location / { + proxy_pass http://127.0.0.1:3060; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # WebSocket-Upgrade (Next.js) + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_read_timeout 120s; + proxy_send_timeout 120s; + } + + listen [::]:443 ssl ipv6only=on; # managed by Certbot + listen 443 ssl; # managed by Certbot + ssl_certificate /etc/letsencrypt/live/nexasign.nexastack.co/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/nexasign.nexastack.co/privkey.pem; # managed by Certbot + include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot + +} +server { + if ($host = nexasign.nexastack.co) { + return 301 https://$host$request_uri; + } # managed by Certbot + + + listen 80; + listen [::]:80; + server_name nexasign.nexastack.co; + return 404; # managed by Certbot + + +} \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index e810a92..15c5e00 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,6 +1,6 @@ -# Docker Setup for NexaSign +# Docker Setup for NexaFile -The following guide will walk you through setting up NexaSign using Docker. You can choose between a production setup using Docker Compose or a standalone container. +The following guide will walk you through setting up NexaFile using Docker. You can choose between a production setup using Docker Compose or a standalone container. ## Prerequisites @@ -11,9 +11,9 @@ Before you begin, ensure that you have the following installed: ## Option 1: Production Docker Compose Setup -This setup includes a PostgreSQL database and the NexaSign application. You will need to provide your own SMTP details via environment variables. +This setup includes a PostgreSQL database and the NexaFile application. You will need to provide your own SMTP details via environment variables. -1. Download the Docker Compose file from the NexaSign repository: [compose.yml](https://raw.githubusercontent.com/nexasign/nexasign/release/docker/production/compose.yml) +1. Download the Docker Compose file from the repository: [compose.yml](https://raw.githubusercontent.com/nexasign/nexasign/release/docker/production/compose.yml) 2. Navigate to the directory containing the `compose.yml` file. 3. Create a `.env` file in the same directory and add your SMTP details as well as a few extra environment variables, following the example below: @@ -84,15 +84,15 @@ NEXT_PRIVATE_SIGNING_PASSPHRASE="" docker-compose --env-file ./.env up -d ``` -This will start the PostgreSQL database and the NexaSign application containers. +This will start the PostgreSQL database and the NexaFile application containers. -6. Access the NexaSign application by visiting `http://localhost:3000` in your web browser. +6. Access the NexaFile application by visiting `http://localhost:3000` in your web browser. ## Option 2: Standalone Docker Container -If you prefer to host the NexaSign application on your container provider of choice, you can use the pre-built Docker image from DockerHub or GitHub's Package Registry. Note that you will need to provide your own database and SMTP host. +If you prefer to host the NexaFile application on your container provider of choice, you can use the pre-built Docker image from DockerHub or GitHub's Package Registry. Note that you will need to provide your own database and SMTP host. -1. Pull the NexaSign Docker image: +1. Pull the NexaFile Docker image: ``` docker pull nexasign/nexasign @@ -126,11 +126,11 @@ docker run -d \ Replace the placeholders with your actual database and SMTP details. -3. Access the NexaSign application by visiting the URL you provided in the `NEXT_PUBLIC_WEBAPP_URL` environment variable in your web browser. +3. Access the NexaFile application by visiting the URL you provided in the `NEXT_PUBLIC_WEBAPP_URL` environment variable in your web browser. ## Success -You have now successfully set up NexaSign using Docker. You can start organizing and managing your documents efficiently. +You have now successfully set up NexaFile using Docker. You can start organizing and managing your documents efficiently. ## Troubleshooting @@ -172,7 +172,7 @@ docker logs -f ### Health Checks -Check the status of your NexaSign instance: +Check the status of your NexaFile instance: ```bash # Basic health check (database + certificate) @@ -194,17 +194,17 @@ The health endpoint will show: 2. **Database connection issues:** Ensure your database is running and accessible 3. **SMTP errors:** Verify your email server settings in the .env file -If you encounter any issues or have further questions, please refer to the official NexaSign documentation or seek assistance from the community. +If you encounter any issues or have further questions, please refer to the official NexaFile documentation or seek assistance from the community. ## Advanced Configuration -The environment variables listed above are a subset of those that are available for configuring NexaSign. For a complete list of environment variables and their descriptions, refer to the table below: +The environment variables listed above are a subset of those that are available for configuring NexaFile. For a complete list of environment variables and their descriptions, refer to the table below: Here's a markdown table documenting all the provided environment variables: | Variable | Description | | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| `PORT` | The port to run the NexaSign application on, defaults to `3000`. | +| `PORT` | The port to run the NexaFile application on, defaults to `3000`. | | `NEXTAUTH_SECRET` | The secret key used by NextAuth.js for encryption and signing. | | `NEXT_PRIVATE_ENCRYPTION_KEY` | The primary encryption key for symmetric encryption and decryption (at least 32 characters). | | `NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY` | The secondary encryption key for symmetric encryption and decryption (at least 32 characters). | diff --git a/docker/nexasign/compose.yml b/docker/nexasign/compose.yml index 2a0e5c3..57248be 100644 --- a/docker/nexasign/compose.yml +++ b/docker/nexasign/compose.yml @@ -73,6 +73,26 @@ services: NEXT_PRIVATE_SIGNING_PASSPHRASE: ${NEXT_PRIVATE_SIGNING_PASSPHRASE} NEXT_PUBLIC_DISABLE_SIGNUP: ${NEXT_PUBLIC_DISABLE_SIGNUP:-false} + + # Discovery — „Dokumente finden". Default 'db' liest aus DiscoveryDocument- + # Tabelle (Source-Sync schreibt dort hinein). Optional 'paperless' oder 'null'. + NEXT_PRIVATE_DISCOVERY_TRANSPORT: ${NEXT_PRIVATE_DISCOVERY_TRANSPORT:-db} + NEXT_PRIVATE_DISCOVERY_PAPERLESS_URL: ${NEXT_PRIVATE_DISCOVERY_PAPERLESS_URL:-} + NEXT_PRIVATE_DISCOVERY_PAPERLESS_TOKEN: ${NEXT_PRIVATE_DISCOVERY_PAPERLESS_TOKEN:-} + + # IMAP-Credential-Encryption. Eigener Key dringend empfohlen (mind. 32 Zeichen). + # Falls leer, fällt der Code auf NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY zurück. + NEXT_PRIVATE_IMAP_CREDENTIAL_KEY: ${NEXT_PRIVATE_IMAP_CREDENTIAL_KEY:-} + # Custom-Hosts erlauben? Default false — nur Mainstream-Provider zulassen. + NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS: ${NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS:-false} + # Optional: zusätzliche Hostnames zur Allowlist (komma-getrennt). + NEXT_PRIVATE_IMAP_HOST_ALLOWLIST: ${NEXT_PRIVATE_IMAP_HOST_ALLOWLIST:-} + + # Discovery-Archiv-Pfad — pro Mail wird ein Ordner mit eml + body + + # Anhängen + metadata.json + sha256-Hashes angelegt. Default ist im + # Container /var/lib/nexasign/sources, gemounted vom Host als + # /var/lib/nexasign-archive (siehe volumes unten). + NEXT_PRIVATE_DISCOVERY_ARCHIVE_PATH: ${NEXT_PRIVATE_DISCOVERY_ARCHIVE_PATH:-/var/lib/nexasign/sources} healthcheck: test: ['CMD-SHELL', 'wget -qO- http://localhost:3000/api/health >/dev/null || exit 1'] interval: 30s @@ -83,6 +103,9 @@ services: - '127.0.0.1:3060:3000' # Host-Port 3060 → Container-Port 3000, nur auf localhost volumes: - nexasign-cert:/opt/nexasign + # Discovery-Archiv: Mails + Anhänge per FTP/SCP vom Host aus erreichbar. + # Default-Host-Pfad /var/lib/nexasign-archive — anpassbar via ARCHIVE_HOST_PATH. + - ${ARCHIVE_HOST_PATH:-/var/lib/nexasign-archive}:/var/lib/nexasign/sources networks: - nexasign-net diff --git a/img/Favicon.png b/img/Favicon.png new file mode 100644 index 0000000..9255777 Binary files /dev/null and b/img/Favicon.png differ diff --git a/img/Logo.png b/img/Logo.png new file mode 100644 index 0000000..c3a61da Binary files /dev/null and b/img/Logo.png differ diff --git a/img/NexaFile Logo.png b/img/NexaFile Logo.png new file mode 100644 index 0000000..5bef15e Binary files /dev/null and b/img/NexaFile Logo.png differ diff --git a/img/NexaFile-Logo.png b/img/NexaFile-Logo.png new file mode 100644 index 0000000..b3d71bd Binary files /dev/null and b/img/NexaFile-Logo.png differ diff --git a/img/NexaFile-Logo.webp b/img/NexaFile-Logo.webp new file mode 100644 index 0000000..f0ad4d6 Binary files /dev/null and b/img/NexaFile-Logo.webp differ diff --git a/img/optimized/android-chrome-192x192.png b/img/optimized/android-chrome-192x192.png new file mode 100644 index 0000000..6a87ffe Binary files /dev/null and b/img/optimized/android-chrome-192x192.png differ diff --git a/img/optimized/android-chrome-512x512.png b/img/optimized/android-chrome-512x512.png new file mode 100644 index 0000000..f0ae06b Binary files /dev/null and b/img/optimized/android-chrome-512x512.png differ diff --git a/img/optimized/apple-touch-icon.png b/img/optimized/apple-touch-icon.png new file mode 100644 index 0000000..397584b Binary files /dev/null and b/img/optimized/apple-touch-icon.png differ diff --git a/img/optimized/favicon-16x16.png b/img/optimized/favicon-16x16.png new file mode 100644 index 0000000..2c173c9 Binary files /dev/null and b/img/optimized/favicon-16x16.png differ diff --git a/img/optimized/favicon-32x32.png b/img/optimized/favicon-32x32.png new file mode 100644 index 0000000..cdc17f6 Binary files /dev/null and b/img/optimized/favicon-32x32.png differ diff --git a/img/optimized/favicon.ico b/img/optimized/favicon.ico new file mode 100644 index 0000000..9749fc5 Binary files /dev/null and b/img/optimized/favicon.ico differ diff --git a/img/optimized/logo-1x.png b/img/optimized/logo-1x.png new file mode 100644 index 0000000..8bb042d Binary files /dev/null and b/img/optimized/logo-1x.png differ diff --git a/img/optimized/logo-1x.webp b/img/optimized/logo-1x.webp new file mode 100644 index 0000000..16fff27 Binary files /dev/null and b/img/optimized/logo-1x.webp differ diff --git a/img/optimized/logo-2x.png b/img/optimized/logo-2x.png new file mode 100644 index 0000000..b5214e4 Binary files /dev/null and b/img/optimized/logo-2x.png differ diff --git a/img/optimized/logo-2x.webp b/img/optimized/logo-2x.webp new file mode 100644 index 0000000..295600d Binary files /dev/null and b/img/optimized/logo-2x.webp differ diff --git a/package-lock.json b/package-lock.json index e1e7229..3f40a29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -351,6 +351,20 @@ "dev": true, "license": "MIT" }, + "apps/docs/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "apps/docs/node_modules/undici-types": { "version": "7.19.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", @@ -446,6 +460,7 @@ "hono-react-router-adapter": "^0.6.5", "input-otp": "^1.4.2", "isbot": "^5.1.32", + "jszip": "^3.10.1", "konva": "^10.0.9", "lucide-react": "^0.554.0", "luxon": "^3.7.2", @@ -13995,6 +14010,30 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mailparser": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/@types/mailparser/-/mailparser-3.4.6.tgz", + "integrity": "sha512-wVV3cnIKzxTffaPH8iRnddX1zahbYB1ZEoAxyhoBo3TBCBuK6nZ8M8JYO/RhsCuuBVOw/DEN/t/ENbruwlxn6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "iconv-lite": "^0.6.3" + } + }, + "node_modules/@types/mailparser/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -14581,6 +14620,17 @@ "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "license": "BSD-2-Clause" }, + "node_modules/@zone-eu/mailsplit": { + "version": "5.4.9", + "resolved": "https://registry.npmjs.org/@zone-eu/mailsplit/-/mailsplit-5.4.9.tgz", + "integrity": "sha512-Qq7k6FzA5SmGf5HFPcr17gE7M+O1gttlmWn7tlGUlhGsbbjUaBL/4cEWIwExeCzqu5+kyZJ91mcBZbQ9zEwwYA==", + "license": "(MIT OR EUPL-1.1+)", + "dependencies": { + "libbase64": "1.3.0", + "libmime": "5.3.8", + "libqp": "2.1.1" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -18308,6 +18358,15 @@ "node": ">= 0.8" } }, + "node_modules/encoding-japanese": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz", + "integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==", + "license": "MIT", + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -21524,6 +21583,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, "node_modules/help-me": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", @@ -21790,6 +21858,97 @@ "node": ">=16.x" } }, + "node_modules/imapflow": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/imapflow/-/imapflow-1.3.3.tgz", + "integrity": "sha512-lx7nWcUDfNgITEKYYfunUDqJ3LT6ImuiA1ReqJepVEA2nqBQNUqa3ppF7Yz5CNjuDYG95pmzsCcNqRjMrwh/Vg==", + "license": "MIT", + "dependencies": { + "@zone-eu/mailsplit": "5.4.9", + "encoding-japanese": "2.2.0", + "iconv-lite": "0.7.2", + "libbase64": "1.3.0", + "libmime": "5.3.8", + "libqp": "2.1.1", + "nodemailer": "8.0.7", + "pino": "10.3.1", + "socks": "2.8.8" + } + }, + "node_modules/imapflow/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/imapflow/node_modules/nodemailer": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.7.tgz", + "integrity": "sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/imapflow/node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/imapflow/node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/imapflow/node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -22095,6 +22254,15 @@ "url": "https://opencollective.com/ioredis" } }, + "node_modules/ip-address": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.1.tgz", + "integrity": "sha512-1FMu8/N15Ck1BL551Jf42NYIoin2unWjLQ2Fze/DXryJRl5twqtwNHlO39qERGbIOcKYWHdgRryhOC+NG4eaLw==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -23066,6 +23234,45 @@ "node": ">=4.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/jwa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", @@ -23290,6 +23497,55 @@ "node": ">= 0.8.0" } }, + "node_modules/libbase64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", + "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", + "license": "MIT" + }, + "node_modules/libmime": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.8.tgz", + "integrity": "sha512-ZrCY+Q66mPvasAfjsQ/IgahzoBvfE1VdtGRpo1hwRB1oK3wJKxhKA3GOcd2a6j7AH5eMFccxK9fBoCpRZTf8ng==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.2.0", + "iconv-lite": "0.7.2", + "libbase64": "1.3.0", + "libqp": "2.1.1" + } + }, + "node_modules/libmime/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/libqp": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz", + "integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==", + "license": "MIT" + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lightningcss": { "version": "1.30.2", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", @@ -23585,6 +23841,15 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/lint-staged": { "version": "16.2.7", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", @@ -24076,6 +24341,75 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/mailparser": { + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.8.tgz", + "integrity": "sha512-7jSlFGXiianVnhnb6wdutJFloD34488nrHY7r6FNqwXAhZ7YiJDYrKKTxZJ0oSrXcAPHm8YoYnh97xyGtrBQ3w==", + "license": "MIT", + "dependencies": { + "@zone-eu/mailsplit": "5.4.8", + "encoding-japanese": "2.2.0", + "he": "1.2.0", + "html-to-text": "9.0.5", + "iconv-lite": "0.7.2", + "libmime": "5.3.8", + "linkify-it": "5.0.0", + "nodemailer": "8.0.5", + "punycode.js": "2.3.1", + "tlds": "1.261.0" + } + }, + "node_modules/mailparser/node_modules/@zone-eu/mailsplit": { + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/@zone-eu/mailsplit/-/mailsplit-5.4.8.tgz", + "integrity": "sha512-eEyACj4JZ7sjzRvy26QhLgKEMWwQbsw1+QZnlLX+/gihcNH07lVPOcnwf5U6UAL7gkc//J3jVd76o/WS+taUiA==", + "license": "(MIT OR EUPL-1.1+)", + "dependencies": { + "libbase64": "1.3.0", + "libmime": "5.3.7", + "libqp": "2.1.1" + } + }, + "node_modules/mailparser/node_modules/@zone-eu/mailsplit/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mailparser/node_modules/@zone-eu/mailsplit/node_modules/libmime": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.7.tgz", + "integrity": "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.2.0", + "iconv-lite": "0.6.3", + "libbase64": "1.3.0", + "libqp": "2.1.1" + } + }, + "node_modules/mailparser/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", @@ -28032,6 +28366,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", @@ -29678,6 +30021,12 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -29929,6 +30278,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -30025,6 +30384,20 @@ } } }, + "node_modules/socks": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.8.tgz", + "integrity": "sha512-NlGELfPrgX2f1TAAcz0WawlLn+0r3FyhhCRpFFK2CemXenPYvzMWWZINv3eDNo9ucdwme7oCHRY0Jnbs4aIkog==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/sonic-boom": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", @@ -31290,6 +31663,15 @@ "node": ">=14.0.0" } }, + "node_modules/tlds": { + "version": "1.261.0", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz", + "integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==", + "license": "MIT", + "bin": { + "tlds": "bin.js" + } + }, "node_modules/tmp": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", @@ -31771,6 +32153,12 @@ "node": "*" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, "node_modules/ufo": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", @@ -33560,12 +33948,15 @@ "ai": "^5.0.104", "bullmq": "^5.71.1", "csv-parse": "^6.1.0", + "imapflow": "^1.0.190", "inngest": "^3.54.0", "ioredis": "^5.10.1", "jose": "^6.1.2", + "jszip": "^3.10.1", "konva": "^10.0.9", "kysely": "0.28.16", "luxon": "^3.7.2", + "mailparser": "^3.7.4", "nanoid": "^5.1.6", "oslo": "^0.17.0", "p-map": "^7.0.4", @@ -33586,6 +33977,7 @@ "devDependencies": { "@playwright/browser-chromium": "1.56.1", "@types/luxon": "^3.7.1", + "@types/mailparser": "^3.4.5", "@types/pg": "^8.15.6", "vitest": "^4.0.18" } diff --git a/packages/assets/logo.png b/packages/assets/logo.png index 983aa6a..49f53e2 100644 Binary files a/packages/assets/logo.png and b/packages/assets/logo.png differ diff --git a/packages/assets/logo_icon.png b/packages/assets/logo_icon.png index cb4765f..6d2af9d 100644 Binary files a/packages/assets/logo_icon.png and b/packages/assets/logo_icon.png differ diff --git a/packages/assets/static/logo.png b/packages/assets/static/logo.png index 4813aaa..49f53e2 100644 Binary files a/packages/assets/static/logo.png and b/packages/assets/static/logo.png differ diff --git a/packages/email/static/logo.png b/packages/email/static/logo.png index 4813aaa..1c27fc3 100644 Binary files a/packages/email/static/logo.png and b/packages/email/static/logo.png differ diff --git a/packages/email/template-components/template-confirmation-email.tsx b/packages/email/template-components/template-confirmation-email.tsx index 19f2513..65ef98c 100644 --- a/packages/email/template-components/template-confirmation-email.tsx +++ b/packages/email/template-components/template-confirmation-email.tsx @@ -18,7 +18,7 @@ export const TemplateConfirmationEmail = ({
- Welcome to NexaSign! + Welcome to NexaFile! diff --git a/packages/email/template-components/template-document-image.tsx b/packages/email/template-components/template-document-image.tsx index f62e1fa..09f9fc1 100644 --- a/packages/email/template-components/template-document-image.tsx +++ b/packages/email/template-components/template-document-image.tsx @@ -16,7 +16,7 @@ export const TemplateDocumentImage = ({ assetBaseUrl, className }: TemplateDocum - NexaSign + NexaFile diff --git a/packages/email/template-components/template-footer.tsx b/packages/email/template-components/template-footer.tsx index a764f22..c18117b 100644 --- a/packages/email/template-components/template-footer.tsx +++ b/packages/email/template-components/template-footer.tsx @@ -1,6 +1,6 @@ import { Trans } from '@lingui/react/macro'; -import { Link, Section, Text } from '../components'; +import { Section, Text } from '../components'; import { useBranding } from '../providers/branding'; export type TemplateFooterProps = { @@ -19,7 +19,7 @@ export const TemplateFooter = ({ isDocument = true }: TemplateFooterProps) => { Footer mit eigener URL ausspielen. Hier keinen externen Link hart-codieren, damit wir nie auf eine Domain zeigen, die der Deployer nicht kontrolliert. */} - This document was sent using NexaSign. + This document was sent using NexaFile. )} @@ -36,11 +36,11 @@ export const TemplateFooter = ({ isDocument = true }: TemplateFooterProps) => { )} - {/* NexaSign ist self-hosted — keine Zentral-Adresse. Wenn der Betreiber + {/* NexaFile ist self-hosted — keine Zentral-Adresse. Wenn der Betreiber in den Team-Einstellungen ein eigenes Branding + Firmenadresse setzt, wird der obige Block mit `brandingCompanyDetails` gerendert. Ohne Branding-Config lassen wir diesen Footer-Abschnitt bewusst leer, - damit keine falsche/NexaSign-Adresse in User-Emails auftaucht. */} + damit keine falsche/NexaFile-Adresse in User-Emails auftaucht. */}
); }; diff --git a/packages/email/templates/access-auth-2fa.tsx b/packages/email/templates/access-auth-2fa.tsx index dc51865..8d81a93 100644 --- a/packages/email/templates/access-auth-2fa.tsx +++ b/packages/email/templates/access-auth-2fa.tsx @@ -47,7 +47,7 @@ export const AccessAuth2FAEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/confirm-email.tsx b/packages/email/templates/confirm-email.tsx index 3e66f36..18827e5 100644 --- a/packages/email/templates/confirm-email.tsx +++ b/packages/email/templates/confirm-email.tsx @@ -33,7 +33,7 @@ export const ConfirmEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/confirm-team-email.tsx b/packages/email/templates/confirm-team-email.tsx index 79e4073..9bff682 100644 --- a/packages/email/templates/confirm-team-email.tsx +++ b/packages/email/templates/confirm-team-email.tsx @@ -39,7 +39,7 @@ export const ConfirmTeamEmailTemplate = ({ const { _ } = useLingui(); const branding = useBranding(); - const previewText = msg`Accept team email request for ${teamName} on NexaSign`; + const previewText = msg`Accept team email request for ${teamName} on NexaFile`; return ( @@ -75,7 +75,7 @@ export const ConfirmTeamEmailTemplate = ({ {teamName} has requested to use your email - address for their team on NexaSign. + address for their team on NexaFile. @@ -105,7 +105,7 @@ export const ConfirmTeamEmailTemplate = ({ - You can revoke access at any time in your team settings on NexaSign{' '} + You can revoke access at any time in your team settings on NexaFile{' '} here. diff --git a/packages/email/templates/document-cancel.tsx b/packages/email/templates/document-cancel.tsx index 847fd50..e53619a 100644 --- a/packages/email/templates/document-cancel.tsx +++ b/packages/email/templates/document-cancel.tsx @@ -39,7 +39,7 @@ export const DocumentCancelTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-completed.tsx b/packages/email/templates/document-completed.tsx index 5277e58..3142e73 100644 --- a/packages/email/templates/document-completed.tsx +++ b/packages/email/templates/document-completed.tsx @@ -40,7 +40,7 @@ export const DocumentCompletedEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-created-from-direct-template.tsx b/packages/email/templates/document-created-from-direct-template.tsx index 9696a3a..a8c3d78 100644 --- a/packages/email/templates/document-created-from-direct-template.tsx +++ b/packages/email/templates/document-created-from-direct-template.tsx @@ -50,7 +50,7 @@ export const DocumentCreatedFromDirectTemplateEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-invite.tsx b/packages/email/templates/document-invite.tsx index 74081de..392e74b 100644 --- a/packages/email/templates/document-invite.tsx +++ b/packages/email/templates/document-invite.tsx @@ -71,7 +71,7 @@ export const DocumentInviteEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-pending.tsx b/packages/email/templates/document-pending.tsx index 947ae1b..9fa4b3a 100644 --- a/packages/email/templates/document-pending.tsx +++ b/packages/email/templates/document-pending.tsx @@ -36,7 +36,7 @@ export const DocumentPendingEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-recipient-signed.tsx b/packages/email/templates/document-recipient-signed.tsx index 92b7dc5..e01f58e 100644 --- a/packages/email/templates/document-recipient-signed.tsx +++ b/packages/email/templates/document-recipient-signed.tsx @@ -44,7 +44,7 @@ export const DocumentRecipientSignedEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-rejected.tsx b/packages/email/templates/document-rejected.tsx index 8e0bd1f..11ba0fe 100644 --- a/packages/email/templates/document-rejected.tsx +++ b/packages/email/templates/document-rejected.tsx @@ -44,7 +44,7 @@ export function DocumentRejectedEmail({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-rejection-confirmed.tsx b/packages/email/templates/document-rejection-confirmed.tsx index 7144d87..304af53 100644 --- a/packages/email/templates/document-rejection-confirmed.tsx +++ b/packages/email/templates/document-rejection-confirmed.tsx @@ -44,7 +44,7 @@ export function DocumentRejectionConfirmedEmail({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-reminder.tsx b/packages/email/templates/document-reminder.tsx index 1e874c6..22a98d2 100644 --- a/packages/email/templates/document-reminder.tsx +++ b/packages/email/templates/document-reminder.tsx @@ -52,7 +52,7 @@ export const DocumentReminderEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-self-signed.tsx b/packages/email/templates/document-self-signed.tsx index e9d0119..584a8f4 100644 --- a/packages/email/templates/document-self-signed.tsx +++ b/packages/email/templates/document-self-signed.tsx @@ -36,7 +36,7 @@ export const DocumentSelfSignedEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/document-super-delete.tsx b/packages/email/templates/document-super-delete.tsx index 8b96964..ca26f22 100644 --- a/packages/email/templates/document-super-delete.tsx +++ b/packages/email/templates/document-super-delete.tsx @@ -39,7 +39,7 @@ export const DocumentSuperDeleteEmailTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/forgot-password.tsx b/packages/email/templates/forgot-password.tsx index 47d3470..61cbea7 100644 --- a/packages/email/templates/forgot-password.tsx +++ b/packages/email/templates/forgot-password.tsx @@ -36,7 +36,7 @@ export const ForgotPasswordTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/organisation-account-link-confirmation.tsx b/packages/email/templates/organisation-account-link-confirmation.tsx index 238b491..6a29fe0 100644 --- a/packages/email/templates/organisation-account-link-confirmation.tsx +++ b/packages/email/templates/organisation-account-link-confirmation.tsx @@ -37,7 +37,7 @@ export const OrganisationAccountLinkConfirmationTemplate = ({ const previewText = type === 'create' ? msg`A request has been made to create an account for you` - : msg`A request has been made to link your NexaSign account`; + : msg`A request has been made to link your NexaFile account`; return ( @@ -69,7 +69,7 @@ export const OrganisationAccountLinkConfirmationTemplate = ({ {type === 'create' ? ( Account creation request ) : ( - Link your NexaSign account + Link your NexaFile account )} @@ -82,7 +82,7 @@ export const OrganisationAccountLinkConfirmationTemplate = ({ ) : ( {organisationName} has requested to link your - current NexaSign account to their organisation. + current NexaFile account to their organisation. )} @@ -110,7 +110,7 @@ export const OrganisationAccountLinkConfirmationTemplate = ({ - You can unlink your account at any time in your security settings on NexaSign{' '} + You can unlink your account at any time in your security settings on NexaFile{' '} here. diff --git a/packages/email/templates/organisation-invite.tsx b/packages/email/templates/organisation-invite.tsx index 92125ce..e41c1f8 100644 --- a/packages/email/templates/organisation-invite.tsx +++ b/packages/email/templates/organisation-invite.tsx @@ -36,7 +36,7 @@ export const OrganisationInviteEmailTemplate = ({ const { _ } = useLingui(); const branding = useBranding(); - const previewText = msg`Accept invitation to join an organisation on NexaSign`; + const previewText = msg`Accept invitation to join an organisation on NexaFile`; return ( @@ -66,7 +66,7 @@ export const OrganisationInviteEmailTemplate = ({
- Join {organisationName} on NexaSign + Join {organisationName} on NexaFile diff --git a/packages/email/templates/organisation-join.tsx b/packages/email/templates/organisation-join.tsx index d642cbc..74ecadf 100644 --- a/packages/email/templates/organisation-join.tsx +++ b/packages/email/templates/organisation-join.tsx @@ -27,7 +27,7 @@ export const OrganisationJoinEmailTemplate = ({ const { _ } = useLingui(); const branding = useBranding(); - const previewText = msg`A member has joined your organisation on NexaSign`; + const previewText = msg`A member has joined your organisation on NexaFile`; return ( diff --git a/packages/email/templates/organisation-leave.tsx b/packages/email/templates/organisation-leave.tsx index 57fc4d5..e022070 100644 --- a/packages/email/templates/organisation-leave.tsx +++ b/packages/email/templates/organisation-leave.tsx @@ -27,7 +27,7 @@ export const OrganisationLeaveEmailTemplate = ({ const { _ } = useLingui(); const branding = useBranding(); - const previewText = msg`A member has left your organisation on NexaSign`; + const previewText = msg`A member has left your organisation on NexaFile`; return ( diff --git a/packages/email/templates/recipient-expired.tsx b/packages/email/templates/recipient-expired.tsx index e1d2fd1..fe934a4 100644 --- a/packages/email/templates/recipient-expired.tsx +++ b/packages/email/templates/recipient-expired.tsx @@ -39,7 +39,7 @@ export const RecipientExpiredTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/recipient-removed-from-document.tsx b/packages/email/templates/recipient-removed-from-document.tsx index 755d8d2..c8f0ebc 100644 --- a/packages/email/templates/recipient-removed-from-document.tsx +++ b/packages/email/templates/recipient-removed-from-document.tsx @@ -38,7 +38,7 @@ export const RecipientRemovedFromDocumentTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/reset-password.tsx b/packages/email/templates/reset-password.tsx index c642d94..3c337cf 100644 --- a/packages/email/templates/reset-password.tsx +++ b/packages/email/templates/reset-password.tsx @@ -38,7 +38,7 @@ export const ResetPasswordTemplate = ({ ) : ( NexaSign Logo )} diff --git a/packages/email/templates/team-email-removed.tsx b/packages/email/templates/team-email-removed.tsx index b486e03..228ecef 100644 --- a/packages/email/templates/team-email-removed.tsx +++ b/packages/email/templates/team-email-removed.tsx @@ -27,7 +27,7 @@ export const TeamEmailRemovedTemplate = ({ const { _ } = useLingui(); const branding = useBranding(); - const previewText = msg`Team email removed for ${teamName} on NexaSign`; + const previewText = msg`Team email removed for ${teamName} on NexaFile`; return ( diff --git a/packages/lib/constants/auth.ts b/packages/lib/constants/auth.ts index 24b69a6..40914ff 100644 --- a/packages/lib/constants/auth.ts +++ b/packages/lib/constants/auth.ts @@ -4,7 +4,7 @@ import { NEXT_PUBLIC_WEBAPP_URL } from './app'; export const SALT_ROUNDS = 12; export const IDENTITY_PROVIDER_NAME: Record = { - NEXASIGN: 'NexaSign', + NEXASIGN: 'NexaFile', GOOGLE: 'Google', MICROSOFT: 'Microsoft', OIDC: 'OIDC', diff --git a/packages/lib/constants/email.ts b/packages/lib/constants/email.ts index fa88ecb..fb55de6 100644 --- a/packages/lib/constants/email.ts +++ b/packages/lib/constants/email.ts @@ -1,7 +1,7 @@ import { env } from '../utils/env'; export const FROM_ADDRESS = env('NEXT_PRIVATE_SMTP_FROM_ADDRESS') || 'noreply@nexastack.co'; -export const FROM_NAME = env('NEXT_PRIVATE_SMTP_FROM_NAME') || 'NexaSign'; +export const FROM_NAME = env('NEXT_PRIVATE_SMTP_FROM_NAME') || 'NexaFile'; export const NEXASIGN_INTERNAL_EMAIL = { name: FROM_NAME, diff --git a/packages/lib/jobs/client.ts b/packages/lib/jobs/client.ts index d0b2c4f..a9f0cd9 100644 --- a/packages/lib/jobs/client.ts +++ b/packages/lib/jobs/client.ts @@ -19,6 +19,7 @@ import { PROCESS_RECIPIENT_EXPIRED_JOB_DEFINITION } from './definitions/internal import { PROCESS_SIGNING_REMINDER_JOB_DEFINITION } from './definitions/internal/process-signing-reminder'; import { SEAL_DOCUMENT_JOB_DEFINITION } from './definitions/internal/seal-document'; import { SEAL_DOCUMENT_SWEEP_JOB_DEFINITION } from './definitions/internal/seal-document-sweep'; +import { RUN_SYNC_RANGE_JOB_DEFINITION } from './definitions/internal/run-sync-range'; import { SEND_SIGNING_REMINDERS_SWEEP_JOB_DEFINITION } from './definitions/internal/send-signing-reminders-sweep'; import { SYNC_EMAIL_DOMAINS_JOB_DEFINITION } from './definitions/internal/sync-email-domains'; @@ -49,6 +50,7 @@ export const jobsClient = new JobClient([ PROCESS_SIGNING_REMINDER_JOB_DEFINITION, CLEANUP_RATE_LIMITS_JOB_DEFINITION, SYNC_EMAIL_DOMAINS_JOB_DEFINITION, + RUN_SYNC_RANGE_JOB_DEFINITION, ] as const); export const jobs = jobsClient; diff --git a/packages/lib/jobs/definitions/internal/run-sync-range.handler.ts b/packages/lib/jobs/definitions/internal/run-sync-range.handler.ts new file mode 100644 index 0000000..e98e59a --- /dev/null +++ b/packages/lib/jobs/definitions/internal/run-sync-range.handler.ts @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { prisma } from '@nexasign/prisma'; + +import { decryptImapConfig } from '../../../server-only/sources/imap'; +import { getSourceAdapter } from '../../../server-only/sources/registry'; +import type { JobRunIO } from '../../client/_internal/job'; +import type { TRunSyncRangeJobDefinition } from './run-sync-range'; + +const SUSPEND_AFTER_FAILURES = 3; + +/** + * Handler für einen einzelnen User-getriggerten Sync-Lauf. + * + * Ablauf: + * 1. SyncRun + Source laden, auf RUNNING setzen. + * 2. Konfig entschlüsseln, Adapter holen. + * 3. adapter.syncRange() mit Cancel-Check + Progress-Updates aufrufen. + * 4. Counter aus dem Adapter-Result in SyncRun schreiben. + * 5. Source.lastSyncAt updaten bei Erfolg, consecutiveFailures bei Login-Fehler. + * 6. Audit-Logs schreiben (STARTED, COMPLETED oder LOGIN_FAILED). + */ +export const run = async ({ + payload, + io, +}: { + payload: TRunSyncRangeJobDefinition; + io: JobRunIO; +}) => { + const { syncRunId } = payload; + + const syncRun = await prisma.syncRun.findUnique({ + where: { id: syncRunId }, + include: { source: true }, + }); + + if (!syncRun) { + io.logger.warn(`SyncRun ${syncRunId} disappeared`); + return; + } + + if (syncRun.status !== 'PENDING') { + io.logger.info(`SyncRun ${syncRunId} skipped: status=${syncRun.status}`); + return; + } + + const source = syncRun.source; + + // Source kann zwischen Trigger und Job-Start gesperrt worden sein. + if (source.lastSyncStatus === 'SUSPENDED') { + await prisma.syncRun.update({ + where: { id: syncRun.id }, + data: { + status: 'FAILED', + errorMessage: 'Quelle ist gesperrt.', + finishedAt: new Date(), + }, + }); + return; + } + + // PENDING → RUNNING + await prisma.syncRun.update({ + where: { id: syncRun.id }, + data: { status: 'RUNNING' }, + }); + + await prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_SYNC_STARTED', + sourceId: source.id, + userId: syncRun.triggeredById, + teamId: source.teamId, + metadata: { + syncRunId: syncRun.id, + rangeFrom: syncRun.rangeFrom.toISOString(), + rangeTo: syncRun.rangeTo.toISOString(), + searchTerm: syncRun.searchTerm, + }, + }, + }); + + const adapter = getSourceAdapter(source.kind); + if (!adapter) { + await prisma.syncRun.update({ + where: { id: syncRun.id }, + data: { + status: 'FAILED', + errorMessage: `Kein Adapter für Source-Typ "${source.kind}" registriert.`, + finishedAt: new Date(), + }, + }); + return; + } + + let decryptedConfig: unknown; + try { + decryptedConfig = decryptImapConfig({ + ciphertext: source.encryptedConfig, + keyVersion: source.encryptedConfigKeyVersion, + }); + } catch (err) { + const message = err instanceof Error ? err.message : 'Konfig-Decrypt fehlgeschlagen'; + await prisma.syncRun.update({ + where: { id: syncRun.id }, + data: { + status: 'FAILED', + errorMessage: message, + finishedAt: new Date(), + }, + }); + return; + } + + // Cancel-Check: liest cancelRequested aus DB. Adapter ruft das pro Mail. + const isCancelled = async (): Promise => { + const fresh = await prisma.syncRun.findUnique({ + where: { id: syncRun.id }, + select: { cancelRequested: true }, + }); + return fresh?.cancelRequested ?? false; + }; + + // Progress-Update: schreibt Counter regelmäßig in die DB, damit das UI + // beim Polling den aktuellen Stand sieht. + const onProgress = async (progress: { + mailsChecked: number; + documentsAuto: number; + documentsManual: number; + documentsIgnored: number; + documentsFailed: number; + }): Promise => { + await prisma.syncRun.update({ + where: { id: syncRun.id }, + data: progress, + }); + }; + + try { + const result = await adapter.syncRange({ + sourceId: source.id, + userId: source.userId, + teamId: source.teamId, + from: syncRun.rangeFrom, + to: syncRun.rangeTo, + searchTerm: syncRun.searchTerm, + decryptedConfig, + isCancelled, + onProgress, + }); + + const wasCancelled = await isCancelled(); + const finalStatus = wasCancelled ? 'CANCELLED' : 'SUCCESS'; + + await prisma.$transaction([ + prisma.syncRun.update({ + where: { id: syncRun.id }, + data: { + status: finalStatus, + mailsChecked: result.mailsChecked, + documentsAuto: result.documentsAuto, + documentsManual: result.documentsManual, + documentsIgnored: result.documentsIgnored, + documentsFailed: result.documentsFailed, + finishedAt: new Date(), + }, + }), + prisma.source.update({ + where: { id: source.id }, + data: { + lastSyncAt: new Date(), + lastSyncStatus: 'SUCCESS', + lastSyncError: null, + consecutiveFailures: 0, + }, + }), + prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_SYNC_COMPLETED', + sourceId: source.id, + userId: syncRun.triggeredById, + teamId: source.teamId, + metadata: { + syncRunId: syncRun.id, + status: finalStatus, + searchTerm: syncRun.searchTerm, + mailsChecked: result.mailsChecked, + documentsAuto: result.documentsAuto, + documentsManual: result.documentsManual, + documentsIgnored: result.documentsIgnored, + }, + }, + }), + ]); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + const newFailures = source.consecutiveFailures + 1; + const shouldSuspend = newFailures >= SUSPEND_AFTER_FAILURES; + + await prisma.$transaction([ + prisma.syncRun.update({ + where: { id: syncRun.id }, + data: { + status: 'FAILED', + errorMessage: message, + finishedAt: new Date(), + }, + }), + prisma.source.update({ + where: { id: source.id }, + data: { + lastSyncStatus: shouldSuspend ? 'SUSPENDED' : 'FAILED', + lastSyncError: message, + consecutiveFailures: newFailures, + }, + }), + prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_SYNC_LOGIN_FAILED', + sourceId: source.id, + userId: syncRun.triggeredById, + metadata: { syncRunId: syncRun.id, error: message, suspended: shouldSuspend }, + }, + }), + ]); + } +}; diff --git a/packages/lib/jobs/definitions/internal/run-sync-range.ts b/packages/lib/jobs/definitions/internal/run-sync-range.ts new file mode 100644 index 0000000..27c6f28 --- /dev/null +++ b/packages/lib/jobs/definitions/internal/run-sync-range.ts @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +import { z } from 'zod'; + +import { type JobDefinition } from '../../client/_internal/job'; + +const RUN_SYNC_RANGE_JOB_DEFINITION_ID = 'internal.run-sync-range'; + +const RUN_SYNC_RANGE_JOB_DEFINITION_SCHEMA = z.object({ + syncRunId: z.string(), +}); + +export type TRunSyncRangeJobDefinition = z.infer; + +/** + * User-getriggerter Sync-Lauf über einen expliziten Zeitraum. Job lädt den + * SyncRun-Record (enthält rangeFrom/rangeTo), dispatcht zum SourceAdapter und + * schreibt Counter zurück. Cron-Auto-Sync existiert nicht — jeder Lauf wird + * vom User in der UI ausgelöst. + */ +export const RUN_SYNC_RANGE_JOB_DEFINITION = { + id: RUN_SYNC_RANGE_JOB_DEFINITION_ID, + name: 'Run Sync Range', + version: '1.0.0', + optimizeParallelism: true, + trigger: { + name: RUN_SYNC_RANGE_JOB_DEFINITION_ID, + schema: RUN_SYNC_RANGE_JOB_DEFINITION_SCHEMA, + }, + handler: async ({ payload, io }) => { + const handler = await import('./run-sync-range.handler'); + await handler.run({ payload, io }); + }, +} as const satisfies JobDefinition< + typeof RUN_SYNC_RANGE_JOB_DEFINITION_ID, + TRunSyncRangeJobDefinition +>; diff --git a/packages/lib/package.json b/packages/lib/package.json index 7e08e40..1b9cbaa 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -47,11 +47,14 @@ "bullmq": "^5.71.1", "csv-parse": "^6.1.0", "inngest": "^3.54.0", + "imapflow": "^1.0.190", "ioredis": "^5.10.1", "jose": "^6.1.2", + "jszip": "^3.10.1", "konva": "^10.0.9", "kysely": "0.28.16", "luxon": "^3.7.2", + "mailparser": "^3.7.4", "nanoid": "^5.1.6", "oslo": "^0.17.0", "p-map": "^7.0.4", @@ -72,6 +75,7 @@ "devDependencies": { "@playwright/browser-chromium": "1.56.1", "@types/luxon": "^3.7.1", + "@types/mailparser": "^3.4.5", "@types/pg": "^8.15.6", "vitest": "^4.0.18" } diff --git a/packages/lib/server-only/2fa/email/generate-2fa-credentials-from-email.ts b/packages/lib/server-only/2fa/email/generate-2fa-credentials-from-email.ts index 9336c63..57da450 100644 --- a/packages/lib/server-only/2fa/email/generate-2fa-credentials-from-email.ts +++ b/packages/lib/server-only/2fa/email/generate-2fa-credentials-from-email.ts @@ -4,7 +4,7 @@ import { createTOTPKeyURI } from 'oslo/otp'; import { NEXASIGN_ENCRYPTION_KEY } from '../../../constants/crypto'; -const ISSUER = 'NexaSign Email 2FA'; +const ISSUER = 'NexaFile Email 2FA'; export type GenerateTwoFactorCredentialsFromEmailOptions = { envelopeId: string; diff --git a/packages/lib/server-only/2fa/setup-2fa.ts b/packages/lib/server-only/2fa/setup-2fa.ts index 595bb2b..db43119 100644 --- a/packages/lib/server-only/2fa/setup-2fa.ts +++ b/packages/lib/server-only/2fa/setup-2fa.ts @@ -12,7 +12,7 @@ type SetupTwoFactorAuthenticationOptions = { user: Pick; }; -const ISSUER = 'NexaSign'; +const ISSUER = 'NexaFile'; export const setupTwoFactorAuthentication = async ({ user, diff --git a/packages/lib/server-only/auth/send-forgot-password.ts b/packages/lib/server-only/auth/send-forgot-password.ts index a41eb9d..4c9d60d 100644 --- a/packages/lib/server-only/auth/send-forgot-password.ts +++ b/packages/lib/server-only/auth/send-forgot-password.ts @@ -56,7 +56,7 @@ export const sendForgotPassword = async ({ userId }: SendForgotPasswordOptions) name: user.name || '', }, from: { - name: env('NEXT_PRIVATE_SMTP_FROM_NAME') || 'NexaSign', + name: env('NEXT_PRIVATE_SMTP_FROM_NAME') || 'NexaFile', address: env('NEXT_PRIVATE_SMTP_FROM_ADDRESS') || 'noreply@nexasign.com', }, subject: i18n._(msg`Forgot Password?`), diff --git a/packages/lib/server-only/auth/send-reset-password.ts b/packages/lib/server-only/auth/send-reset-password.ts index 899ec32..d102a73 100644 --- a/packages/lib/server-only/auth/send-reset-password.ts +++ b/packages/lib/server-only/auth/send-reset-password.ts @@ -38,7 +38,7 @@ export const sendResetPassword = async ({ userId }: SendResetPasswordOptions) => name: user.name || '', }, from: { - name: env('NEXT_PRIVATE_SMTP_FROM_NAME') || 'NexaSign', + name: env('NEXT_PRIVATE_SMTP_FROM_NAME') || 'NexaFile', address: env('NEXT_PRIVATE_SMTP_FROM_ADDRESS') || 'noreply@nexasign.com', }, subject: 'Password Reset Success!', diff --git a/packages/lib/server-only/cert/cert-status.ts b/packages/lib/server-only/cert/cert-status.ts index 79bdb76..59e1fdf 100644 --- a/packages/lib/server-only/cert/cert-status.ts +++ b/packages/lib/server-only/cert/cert-status.ts @@ -87,6 +87,6 @@ export const assertSigningCertificateConfigured = () => { throw new AppError(AppErrorCode.NOT_SETUP, { message: `Signing certificate is not available at ${status.filePath} (${status.reason}).`, userMessage: - 'NexaSign needs a signing certificate before documents can be sent for signature. Configure cert.p12 or run scripts/nexasign/generate-dev-cert.sh for a test certificate.', + 'NexaFile needs a signing certificate before documents can be sent for signature. Configure cert.p12 or run scripts/nexasign/generate-dev-cert.sh for a test certificate.', }); }; diff --git a/packages/lib/server-only/discovery/get-discovery-reader.ts b/packages/lib/server-only/discovery/get-discovery-reader.ts new file mode 100644 index 0000000..d2edd0e --- /dev/null +++ b/packages/lib/server-only/discovery/get-discovery-reader.ts @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { env } from '@nexasign/lib/utils/env'; + +import { dbDiscoveryReader } from './readers/db-reader'; +import { nullDiscoveryReader } from './readers/null-reader'; +import { paperlessDiscoveryReader } from './readers/paperless-reader'; +import type { DiscoveryReader } from './types'; + +/** + * Wählt den Discovery-Reader anhand der Environment-Konfiguration. + * + * NEXT_PRIVATE_DISCOVERY_TRANSPORT bestimmt das Backend: + * - "db" (Default) → liest aus der DiscoveryDocument-Tabelle. Source-Sync + * (IMAP, später Cloud) und manueller Upload schreiben dort + * hinein. + * - "paperless" → externer Indexdienst per REST. + * - "null" → Stub, leere Listen. + * + * Der Aufrufer kennt nur das `DiscoveryReader`-Interface. + */ +export const getDiscoveryReader = (): DiscoveryReader => { + const transport = env('NEXT_PRIVATE_DISCOVERY_TRANSPORT') ?? 'db'; + + if (transport === 'paperless') { + return paperlessDiscoveryReader; + } + if (transport === 'null') { + return nullDiscoveryReader; + } + return dbDiscoveryReader; +}; + +/** + * True, wenn der aktive Reader echte Daten liefern kann (kein null-Stub). + */ +export const isDiscoveryConfigured = (): boolean => { + return getDiscoveryReader().id !== 'null'; +}; diff --git a/packages/lib/server-only/discovery/index.ts b/packages/lib/server-only/discovery/index.ts new file mode 100644 index 0000000..3ba5bfe --- /dev/null +++ b/packages/lib/server-only/discovery/index.ts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +export { getDiscoveryReader, isDiscoveryConfigured } from './get-discovery-reader'; +export type { + DiscoveryContext, + DiscoveryDocument, + DiscoveryDocumentStatus, + DiscoveryFilter, + DiscoveryPage, + DiscoveryReader, +} from './types'; diff --git a/packages/lib/server-only/discovery/readers/db-reader.ts b/packages/lib/server-only/discovery/readers/db-reader.ts new file mode 100644 index 0000000..981a06d --- /dev/null +++ b/packages/lib/server-only/discovery/readers/db-reader.ts @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import type { + Prisma, + DiscoveryDocumentStatus as PrismaDiscoveryDocumentStatus, +} from '@prisma/client'; + +import { AppError, AppErrorCode } from '@nexasign/lib/errors/app-error'; +import { prisma } from '@nexasign/prisma'; + +import type { + DiscoveryContext, + DiscoveryDocument, + DiscoveryDocumentStatus, + DiscoveryFilter, + DiscoveryPage, + DiscoveryReader, +} from '../types'; + +/** + * DB-Reader — Default-Reader, liest aus der `DiscoveryDocument`-Tabelle. + * + * Source-Adapter (IMAP, später Cloud) und der manuelle Intake-Upload schreiben + * dort hinein; dieser Reader liest nur, kein Schreib-Pfad. + * + * Mehrtenant: jedes Dokument ist team-gebunden. Für IMAP-importierte Dokumente + * gilt zusätzlich `uploadedById === ctx.userId` — User A sieht User Bs Belege + * im selben Team nicht. + */ + +const PAGE_SIZE = 25; + +const NATIVE_TO_UI_STATUS: Record = { + INBOX: 'inbox', + PENDING_MANUAL: 'pending-manual', + ACCEPTED: 'accepted', + SIGNED: 'accepted', // signed ist eine Spezialform von akzeptiert + ARCHIVED: 'archived', + IGNORED: 'ignored', +}; + +const UI_TO_NATIVE_STATUS: Record = { + inbox: ['INBOX'], + 'pending-manual': ['PENDING_MANUAL'], + accepted: ['ACCEPTED', 'SIGNED'], + archived: ['ARCHIVED'], + ignored: ['IGNORED'], + processed: ['ACCEPTED', 'SIGNED', 'ARCHIVED', 'IGNORED'], +}; + +const requireTeam = (ctx: DiscoveryContext | undefined): number => { + if (!ctx?.teamId) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Discovery braucht einen Team-Kontext.', + }); + } + return ctx.teamId; +}; + +type DbDiscoveryDocument = { + id: string; + title: string; + correspondent: string | null; + documentType: string | null; + documentDate: Date | null; + capturedAt: Date; + status: PrismaDiscoveryDocumentStatus; + contentType: string | null; + tags: string[]; + detectedAmount: string | null; + detectedInvoiceNumber: string | null; + acceptedAt: Date | null; + acceptedBy: { name: string | null } | null; + archivePath: string | null; + dataId: string | null; + signingEnvelopeId: string | null; + _count: { artifacts: number }; +}; + +const toDiscoveryDocument = (doc: DbDiscoveryDocument): DiscoveryDocument => { + // attachmentCount = Anzahl ATTACHMENT-Artifacts. _count.artifacts liefert + // alle Artifacts (inkl. MAIL_EML/BODY/METADATA), wir interessieren uns aber + // nur für die User-sichtbaren Anhaenge. Vereinfacht: wenn _count > 1, dann + // hat die Mail mind. einen ATTACHMENT (jeder Sync schreibt 3 Standard- + // Artifacts: EML+BODY_TEXT+METADATA — alles drueber sind Anhaenge). + // Exakt waere ein separater count, aber das ist N+1 — fuer V1 reicht die + // Heuristik. Spaeter: dedizierter count via where-Clause auf kind=ATTACHMENT. + const attachmentCount = Math.max(0, doc._count.artifacts - 3); + const hasArchive = doc.archivePath !== null && doc.archivePath !== '' && doc._count.artifacts > 0; + + return { + id: doc.id, + nativeId: doc.id, + title: doc.title, + correspondent: doc.correspondent, + documentType: doc.documentType, + tags: doc.tags, + documentDate: doc.documentDate, + capturedAt: doc.capturedAt, + status: NATIVE_TO_UI_STATUS[doc.status] ?? 'inbox', + detectedAmount: doc.detectedAmount, + detectedInvoiceNumber: doc.detectedInvoiceNumber, + acceptedAt: doc.acceptedAt, + acceptedByName: doc.acceptedBy?.name ?? null, + attachmentCount, + hasArchive, + signingEnvelopeId: doc.signingEnvelopeId, + canCreateSigningDocument: doc.dataId !== null || hasArchive, + }; +}; + +const buildWhere = ( + teamId: number, + userId: number | undefined, + filter: DiscoveryFilter, +): Prisma.DiscoveryDocumentWhereInput => { + const where: Prisma.DiscoveryDocumentWhereInput = { teamId }; + + // Multi-User-Isolation: Belege aus IMAP-Quellen sind privat — nur ihr Owner + // sieht sie. Lokale Uploads (providerSource = 'local') bleiben Team-sichtbar. + if (userId !== undefined) { + where.OR = [{ providerSource: 'local' }, { uploadedById: userId }]; + } + + // 'all' überspringt den Status-Filter — Hauptanwendungsfall „Überblick". + if (filter.status && filter.status !== 'all') { + where.status = { in: UI_TO_NATIVE_STATUS[filter.status] }; + } + + if (filter.query) { + const text = filter.query; + const textFilter = [ + { title: { contains: text, mode: 'insensitive' as const } }, + { correspondent: { contains: text, mode: 'insensitive' as const } }, + ]; + where.AND = [{ OR: textFilter }]; + } + + if (filter.correspondent) { + where.correspondent = { contains: filter.correspondent, mode: 'insensitive' }; + } + + if (filter.documentDateFrom || filter.documentDateTo) { + where.documentDate = { + gte: filter.documentDateFrom, + lt: filter.documentDateTo, + }; + } + + return where; +}; + +export const dbDiscoveryReader: DiscoveryReader = { + id: 'db', + + async findDocuments( + filter: DiscoveryFilter, + cursor?: string | null, + ctx?: DiscoveryContext, + ): Promise { + const teamId = requireTeam(ctx); + const where = buildWhere(teamId, ctx?.userId, filter); + + const [total, results] = await Promise.all([ + prisma.discoveryDocument.count({ where }), + prisma.discoveryDocument.findMany({ + where, + // Dokumentdatum vor capturedAt — User will chronologische Sicht über + // den Belegzeitraum, nicht über den Sync-Zeitpunkt. + orderBy: [{ documentDate: 'desc' }, { capturedAt: 'desc' }], + take: PAGE_SIZE + 1, + ...(cursor ? { cursor: { id: cursor }, skip: 1 } : {}), + include: { + acceptedBy: { select: { name: true } }, + // attachmentCount/hasArchive ableiten — siehe toDiscoveryDocument(). + _count: { select: { artifacts: true } }, + }, + }), + ]); + + const hasMore = results.length > PAGE_SIZE; + const slice = hasMore ? results.slice(0, PAGE_SIZE) : results; + + return { + documents: slice.map(toDiscoveryDocument), + total, + nextCursor: hasMore ? slice[slice.length - 1].id : null, + }; + }, + + async getDocument(id: string, ctx?: DiscoveryContext): Promise { + const teamId = requireTeam(ctx); + const where = buildWhere(teamId, ctx?.userId, {}); + const doc = await prisma.discoveryDocument.findFirst({ + where: { ...where, id }, + include: { + acceptedBy: { select: { name: true } }, + _count: { select: { artifacts: true } }, + }, + }); + return doc ? toDiscoveryDocument(doc) : null; + }, + + async getDocumentContent(id: string, ctx?: DiscoveryContext): Promise { + const teamId = requireTeam(ctx); + const where = buildWhere(teamId, ctx?.userId, {}); + const doc = await prisma.discoveryDocument.findFirst({ + where: { ...where, id }, + include: { data: true }, + }); + if (!doc) return null; + if (!doc.data) return null; + + // Speicher-Provider abstrahiert Binär-Inhalte als String (Base64 oder S3-Key). + // Tatsächliches Streaming bleibt dem Storage-Layer überlassen. + if (doc.data.type === 'BYTES_64') { + const { base64 } = await import('@scure/base'); + return base64.decode(doc.data.data); + } + + // S3_PATH: hier müsste der Storage-Provider den Stream liefern. + // Für V1 kein direktes Bytes-Lesen aus S3 vom Reader aus. + return null; + }, +}; diff --git a/packages/lib/server-only/discovery/readers/null-reader.ts b/packages/lib/server-only/discovery/readers/null-reader.ts new file mode 100644 index 0000000..90b7ddd --- /dev/null +++ b/packages/lib/server-only/discovery/readers/null-reader.ts @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import type { DiscoveryContext, DiscoveryFilter, DiscoveryPage, DiscoveryReader } from '../types'; + +/** + * Stub-Reader — wird nur explizit aktiviert, wenn ein Setup absichtlich kein + * Discovery-Backend hat. In allen anderen Fällen ist der DB-Reader der Default. + */ +export const nullDiscoveryReader: DiscoveryReader = { + id: 'null', + + async findDocuments( + _filter: DiscoveryFilter, + _cursor?: string | null, + _ctx?: DiscoveryContext, + ): Promise { + return Promise.resolve({ documents: [], total: 0, nextCursor: null }); + }, + + async getDocument(_id: string, _ctx?: DiscoveryContext) { + return Promise.resolve(null); + }, + + async getDocumentContent(_id: string, _ctx?: DiscoveryContext) { + return Promise.resolve(null); + }, +}; diff --git a/packages/lib/server-only/discovery/readers/paperless-reader.ts b/packages/lib/server-only/discovery/readers/paperless-reader.ts new file mode 100644 index 0000000..2ff7cf4 --- /dev/null +++ b/packages/lib/server-only/discovery/readers/paperless-reader.ts @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { env } from '@nexasign/lib/utils/env'; + +import type { + DiscoveryContext, + DiscoveryDocument, + DiscoveryDocumentStatus, + DiscoveryFilter, + DiscoveryPage, + DiscoveryReader, +} from '../types'; + +/** + * Discovery-Provider auf Basis eines externen Indexdienstes (REST-Backend). + * + * Konfiguration via Environment: + * NEXT_PRIVATE_DISCOVERY_TRANSPORT=paperless + * NEXT_PRIVATE_DISCOVERY_PAPERLESS_URL=https:// + * NEXT_PRIVATE_DISCOVERY_PAPERLESS_TOKEN= + * + * Hinweis (Lizenz): Dieser Provider spricht mit Paperless-ngx (GPL-3.0). + * Die Erwähnung an dieser Stelle erfüllt die Attribution-Pflicht. Im + * NexaFile-UI wird der Backend-Name nicht angezeigt. + */ + +type PaperlessDocument = { + id: number; + title: string; + correspondent: number | null; + document_type: number | null; + tags: number[]; + created: string; + added: string; + modified: string; + content?: string; + archive_serial_number?: string | null; + original_file_name?: string; +}; + +type PaperlessListResponse = { + count: number; + next: string | null; + previous: string | null; + results: PaperlessDocument[]; +}; + +type LookupCache = { + correspondents: Map; + tags: Map; + documentTypes: Map; + fetchedAt: number; +}; + +const LOOKUP_TTL_MS = 5 * 60 * 1000; +const PAGE_SIZE = 25; +const STATUS_TAG_MANUAL = 'manuell-zu-ziehen'; +const STATUS_TAG_PROCESSED = 'verarbeitet'; + +let lookupCache: LookupCache | null = null; + +const getConfig = () => { + const baseUrl = env('NEXT_PRIVATE_DISCOVERY_PAPERLESS_URL'); + const token = env('NEXT_PRIVATE_DISCOVERY_PAPERLESS_TOKEN'); + + if (!baseUrl || !token) { + throw new Error( + 'Discovery-Provider nicht vollständig konfiguriert: ' + + 'NEXT_PRIVATE_DISCOVERY_PAPERLESS_URL und _TOKEN müssen gesetzt sein.', + ); + } + + return { + baseUrl: baseUrl.replace(/\/+$/, ''), + token, + }; +}; + +const apiFetch = async (path: string): Promise => { + const { baseUrl, token } = getConfig(); + const url = path.startsWith('http') ? path : `${baseUrl}${path}`; + + const response = await fetch(url, { + headers: { + Authorization: `Token ${token}`, + Accept: 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`Discovery-Backend antwortet mit ${response.status}: ${response.statusText}`); + } + + return response.json(); +}; + +const refreshLookups = async (): Promise => { + if (lookupCache && Date.now() - lookupCache.fetchedAt < LOOKUP_TTL_MS) { + return lookupCache; + } + + type Named = { id: number; name: string }; + type ListOf = { results: T[]; next: string | null }; + + const fetchAll = async (path: string): Promise => { + const all: T[] = []; + let cursor: string | null = path; + while (cursor) { + const page: ListOf = await apiFetch>(cursor); + all.push(...page.results); + cursor = page.next; + } + return all; + }; + + const [correspondents, tags, documentTypes] = await Promise.all([ + fetchAll('/api/correspondents/?page_size=100'), + fetchAll('/api/tags/?page_size=100'), + fetchAll('/api/document_types/?page_size=100'), + ]); + + const nextLookupCache = { + correspondents: new Map(correspondents.map((c) => [c.id, c.name])), + tags: new Map(tags.map((t) => [t.id, t.name])), + documentTypes: new Map(documentTypes.map((d) => [d.id, d.name])), + fetchedAt: Date.now(), + }; + + // Benign: parallele Refreshes koennen denselben Lookup-Cache ueberschreiben. + // eslint-disable-next-line require-atomic-updates + lookupCache = nextLookupCache; + return nextLookupCache; +}; + +const deriveStatus = (tagNames: string[]): DiscoveryDocumentStatus => { + const lower = tagNames.map((t) => t.toLowerCase()); + if (lower.includes(STATUS_TAG_PROCESSED)) { + return 'processed'; + } + if (lower.includes(STATUS_TAG_MANUAL)) { + return 'pending-manual'; + } + return 'inbox'; +}; + +const toDiscoveryDocument = (doc: PaperlessDocument, lookups: LookupCache): DiscoveryDocument => { + const tagNames = doc.tags + .map((id) => lookups.tags.get(id)) + .filter((name): name is string => Boolean(name)); + + return { + id: `paperless:${doc.id}`, + nativeId: String(doc.id), + title: doc.title || doc.original_file_name || `#${doc.id}`, + correspondent: + doc.correspondent !== null ? (lookups.correspondents.get(doc.correspondent) ?? null) : null, + documentType: + doc.document_type !== null ? (lookups.documentTypes.get(doc.document_type) ?? null) : null, + tags: tagNames, + documentDate: doc.created ? new Date(doc.created) : null, + capturedAt: doc.added ? new Date(doc.added) : new Date(), + status: deriveStatus(tagNames), + // Paperless-Quellen liefern immer ein Document mit binär-Inhalt — daher + // counted: 1 Anhang, hasArchive true. Kein File-System-Archive wie bei IMAP. + attachmentCount: 1, + hasArchive: true, + }; +}; + +const buildQueryString = (filter: DiscoveryFilter, cursor?: string | null): string => { + const params = new URLSearchParams(); + params.set('page_size', String(PAGE_SIZE)); + params.set('ordering', '-added'); + + if (cursor) { + params.set('page', cursor); + } + if (filter.query) { + params.set('query', filter.query); + } + if (filter.documentDateFrom) { + params.set('created__date__gte', filter.documentDateFrom.toISOString().slice(0, 10)); + } + if (filter.documentDateTo) { + params.set('created__date__lt', filter.documentDateTo.toISOString().slice(0, 10)); + } + if (filter.status === 'pending-manual') { + params.set('tags__name__iexact', STATUS_TAG_MANUAL); + } + if (filter.status === 'processed') { + params.set('tags__name__iexact', STATUS_TAG_PROCESSED); + } + + return params.toString(); +}; + +const extractCursorFromUrl = (url: string | null): string | null => { + if (!url) return null; + try { + const u = new URL(url); + return u.searchParams.get('page'); + } catch { + return null; + } +}; + +const parseId = (id: string): string => { + return id.startsWith('paperless:') ? id.slice('paperless:'.length) : id; +}; + +export const paperlessDiscoveryReader: DiscoveryReader = { + id: 'paperless', + + async findDocuments( + filter: DiscoveryFilter, + cursor?: string | null, + _ctx?: DiscoveryContext, + ): Promise { + const lookups = await refreshLookups(); + const qs = buildQueryString(filter, cursor); + const page = await apiFetch(`/api/documents/?${qs}`); + + let documents = page.results.map((doc) => toDiscoveryDocument(doc, lookups)); + + // Status-Filter „inbox" lässt sich nicht direkt abfragen (Abwesenheit von Tags), + // daher clientseitig nachfiltern. + if (filter.status === 'inbox') { + documents = documents.filter((d) => d.status === 'inbox'); + } + + if (filter.correspondent) { + const needle = filter.correspondent.toLowerCase(); + documents = documents.filter((d) => d.correspondent?.toLowerCase().includes(needle)); + } + + return { + documents, + total: page.count, + nextCursor: extractCursorFromUrl(page.next), + }; + }, + + async getDocument(id: string, _ctx?: DiscoveryContext): Promise { + const lookups = await refreshLookups(); + try { + const doc = await apiFetch(`/api/documents/${parseId(id)}/`); + return toDiscoveryDocument(doc, lookups); + } catch { + return null; + } + }, + + async getDocumentContent(id: string, _ctx?: DiscoveryContext): Promise { + const { baseUrl, token } = getConfig(); + const response = await fetch(`${baseUrl}/api/documents/${parseId(id)}/download/`, { + headers: { Authorization: `Token ${token}` }, + }); + if (!response.ok) return null; + const buffer = await response.arrayBuffer(); + return new Uint8Array(buffer); + }, +}; diff --git a/packages/lib/server-only/discovery/types.ts b/packages/lib/server-only/discovery/types.ts new file mode 100644 index 0000000..3564e19 --- /dev/null +++ b/packages/lib/server-only/discovery/types.ts @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +/** + * Discovery-Schicht: Datenstrukturen für „Dokumente finden". + * + * Diese Typen sind backend-agnostisch. Ein Reader übersetzt zwischen seinem + * nativen Datenmodell und diesen Typen, damit das UI den Reader nicht kennt. + * + * Discovery ist nur Lesen. Schreiben (Source-Sync, Upload) lebt in + * `packages/lib/server-only/sources/` und `packages/lib/server-only/intake/`. + */ + +export type DiscoveryDocumentStatus = + | 'inbox' // Neu eingegangen, noch nicht gesichtet + | 'pending-manual' // Hinweis erkannt, Beleg muss manuell beschafft werden + | 'accepted' // User hat als Geschäftsbeleg akzeptiert (GoBD-WORM aktiv) + | 'archived' // Akzeptiert + archiviert (10-Jahres-Aufbewahrung läuft weiter) + | 'ignored' // User hat als irrelevant markiert + | 'processed'; // Sammel-Filter: accepted ∪ archived ∪ ignored ∪ signed + +export type DiscoveryDocument = { + /** Stabile, readerunabhängige ID */ + id: string; + /** Reader-interne ID, falls für Detail-Aufrufe nötig */ + nativeId: string; + /** Anzeigentitel des Dokuments */ + title: string; + /** Korrespondent/Aussteller, falls erkannt */ + correspondent: string | null; + /** Inhaltlicher Typ (z.B. „Rechnung", „Vertrag") */ + documentType: string | null; + /** Tags vom Backend */ + tags: string[]; + /** Datum, das auf dem Dokument selbst steht (Belegdatum), falls erkannt */ + documentDate: Date | null; + /** Wann es im Discovery-Backend aufgetaucht ist */ + capturedAt: Date; + /** Lifecycle-Status aus Sicht des NexaFile-Nutzers */ + status: DiscoveryDocumentStatus; + /** Optional in Listenansicht (vor allem bei akzeptierten Belegen). */ + detectedAmount?: string | null; + detectedInvoiceNumber?: string | null; + acceptedAt?: Date | null; + acceptedByName?: string | null; + /** + * Anzahl ATTACHMENT-Artifacts mit nicht-leerem archivePath. 0 = nichts + * herunterladbar (entweder MANUAL ohne PDF oder vor-Archive-Sync-Datensatz). + */ + attachmentCount: number; + /** + * Hat das Document einen archivePath gesetzt UND mind. ein Artifact? + * Convenience-Flag fuer UI: Download-Button enable/disable. + */ + hasArchive: boolean; + /** Vorbereitetes Signatur-Dokument aus Schritt 3, falls bereits erzeugt. */ + signingEnvelopeId?: string | null; + /** Ob aus diesem Fund ein Signatur-Dokument erzeugt werden kann. */ + canCreateSigningDocument?: boolean; +}; + +export type DiscoveryListStatusFilter = DiscoveryDocumentStatus | 'all'; + +export type DiscoveryFilter = { + query?: string; + /** + * Status-Filter. 'all' bedeutet: alle Status zeigen — der Hauptzweck der + * Listenansicht ist „welche Mail mit welcher Rechnung wann" — nicht ein + * Workflow-getrennter Tabs-Blick. + */ + status?: DiscoveryListStatusFilter; + correspondent?: string; + documentDateFrom?: Date; + documentDateTo?: Date; +}; + +export type DiscoveryPage = { + documents: DiscoveryDocument[]; + total: number; + nextCursor: string | null; +}; + +/** + * Ausführungs-Kontext aus der Session. Reader, die Multi-Tenancy unterstützen + * (DB-Reader für lokale Uploads + IMAP-Sync), nutzen teamId/userId. Externe + * Reader (Paperless) ignorieren das Feld. + */ +export type DiscoveryContext = { + teamId?: number; + userId?: number; +}; + +export type DiscoveryReader = { + /** Lesbarer Name für Logging/Diagnose, nie dem Nutzer angezeigt */ + readonly id: string; + + findDocuments( + filter: DiscoveryFilter, + cursor?: string | null, + ctx?: DiscoveryContext, + ): Promise; + + getDocument(id: string, ctx?: DiscoveryContext): Promise; + + getDocumentContent(id: string, ctx?: DiscoveryContext): Promise; +}; diff --git a/packages/lib/server-only/email/get-email-context.ts b/packages/lib/server-only/email/get-email-context.ts index 49ab566..c2691d7 100644 --- a/packages/lib/server-only/email/get-email-context.ts +++ b/packages/lib/server-only/email/get-email-context.ts @@ -110,7 +110,7 @@ export const getEmailContext = async ( const senderEmailId = match(meta?.emailId) .with(P.string, (emailId) => emailId) // Explicit string means to use the provided email ID. .with(undefined, () => emailContext.settings.emailId) // Undefined means to use the inherited email ID. - .with(null, () => null) // Explicit null means to use the NexaSign email. + .with(null, () => null) // Explicit null means to use the NexaFile email. .exhaustive(); const foundSenderEmail = emailContext.allowedEmails.find((email) => email.id === senderEmailId); diff --git a/packages/lib/server-only/intake/index.ts b/packages/lib/server-only/intake/index.ts new file mode 100644 index 0000000..a867d9b --- /dev/null +++ b/packages/lib/server-only/intake/index.ts @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +export { uploadIntakeDocument } from './upload-document'; +export type { UploadIntakeDocumentInput } from './upload-document'; diff --git a/packages/lib/server-only/intake/upload-document.ts b/packages/lib/server-only/intake/upload-document.ts new file mode 100644 index 0000000..fbc5e44 --- /dev/null +++ b/packages/lib/server-only/intake/upload-document.ts @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { prisma } from '@nexasign/prisma'; + +import { putFileServerSide } from '../../universal/upload/put-file.server'; +import { createDocumentData } from '../document-data/create-document-data'; + +export type UploadIntakeDocumentInput = { + teamId: number; + userId: number; + fileName: string; + contentType: string; + bytes: Uint8Array; +}; + +/** + * Manueller Datei-Upload — schreibt direkt in `DiscoveryDocument` mit + * `providerSource: 'local'`. Lebt im Intake-Pfad (Schritt 2 des Lifecycles + * „Dokumente erstellen/ablegen"), nicht in Discovery (Schritt 1 = „Finden"). + * + * Für Welle 1 ist diese Funktion nur als geparkte Endstelle aufgehoben — die + * UI darunter wird in einem späteren Schritt aufgebaut. Backend ist bereits + * funktionsfähig. + */ +export const uploadIntakeDocument = async (input: UploadIntakeDocumentInput) => { + const { teamId, userId, fileName, contentType, bytes } = input; + + const filename = fileName || 'dokument.pdf'; + const file = { + name: filename, + type: contentType || 'application/pdf', + arrayBuffer: async () => + Promise.resolve(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)), + }; + + const documentData = await putFileServerSide(file); + const dataRecord = await createDocumentData({ + type: documentData.type, + data: documentData.data, + }); + + const titleFromFile = filename.replace(/\.[^.]+$/, ''); + + return prisma.discoveryDocument.create({ + data: { + teamId, + uploadedById: userId, + title: titleFromFile || filename, + capturedAt: new Date(), + status: 'INBOX', + providerSource: 'local', + contentType, + fileSize: bytes.byteLength, + tags: [], + dataId: dataRecord.id, + }, + }); +}; diff --git a/packages/lib/server-only/organisation/create-organisation-member-invites.ts b/packages/lib/server-only/organisation/create-organisation-member-invites.ts index 7886d4d..cb8a1e7 100644 --- a/packages/lib/server-only/organisation/create-organisation-member-invites.ts +++ b/packages/lib/server-only/organisation/create-organisation-member-invites.ts @@ -214,7 +214,7 @@ export const sendOrganisationMemberInviteEmail = async ({ await mailer.sendMail({ to: email, from: senderEmail, - subject: i18n._(msg`You have been invited to join ${organisation.name} on NexaSign`), + subject: i18n._(msg`You have been invited to join ${organisation.name} on NexaFile`), html, text, }); diff --git a/packages/lib/server-only/sources/archive/archive-writer.test.ts b/packages/lib/server-only/sources/archive/archive-writer.test.ts new file mode 100644 index 0000000..f28071c --- /dev/null +++ b/packages/lib/server-only/sources/archive/archive-writer.test.ts @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +import { createHash } from 'node:crypto'; +import { promises as fs } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { writeArchive } from './archive-writer'; + +const sha256 = (buf: Buffer | Uint8Array): string => + createHash('sha256').update(buf).digest('hex'); + +let testRoot: string; + +const baseInput = { + sourceId: 'src_test', + messageIdHash: 'a'.repeat(64), + receivedAt: new Date('2024-05-15T10:30:00Z'), + rawEml: Buffer.from('From: test@example.com\nSubject: Test\n\nHallo'), + bodyText: 'Hallo Welt', + bodyHtml: null as string | null, + metadata: { foo: 'bar' }, + attachments: [ + { + fileName: 'rechnung.pdf', + contentType: 'application/pdf', + bytes: new Uint8Array(Buffer.from('%PDF-1.4 test')), + }, + ], +}; + +beforeEach(async () => { + testRoot = await fs.mkdtemp(path.join(tmpdir(), 'nexasign-archive-test-')); + process.env.NEXT_PRIVATE_DISCOVERY_ARCHIVE_PATH = testRoot; +}); + +afterEach(async () => { + // Read-only-Dirs müssen vor rm wieder write-bar gemacht werden. + const restoreWritable = async (dir: string): Promise => { + try { + await fs.chmod(dir, 0o700); + const entries = await fs.readdir(dir); + for (const entry of entries) { + const full = path.join(dir, entry); + const stat = await fs.stat(full).catch(() => null); + if (!stat) continue; + if (stat.isDirectory()) { + await restoreWritable(full); + } else { + await fs.chmod(full, 0o600).catch(() => {}); + } + } + } catch { + /* ignore */ + } + }; + await restoreWritable(testRoot); + await fs.rm(testRoot, { recursive: true, force: true }); +}); + +describe('writeArchive', () => { + it('schreibt eml + body + metadata + attachment mit korrekten Hashes', async () => { + const result = await writeArchive(baseInput); + + expect(result.alreadyExisted).toBe(false); + expect(result.archivePath).toMatch(/^src_test\/2024\/05\/a+$/); + + const kinds = result.artifacts.map((a) => a.kind).sort(); + expect(kinds).toEqual(['ATTACHMENT', 'MAIL_BODY_TEXT', 'MAIL_EML', 'MAIL_METADATA']); + + const eml = result.artifacts.find((a) => a.kind === 'MAIL_EML'); + expect(eml?.sha256).toBe(sha256(baseInput.rawEml)); + expect(eml?.fileSize).toBe(baseInput.rawEml.length); + + const body = result.artifacts.find((a) => a.kind === 'MAIL_BODY_TEXT'); + expect(body?.sha256).toBe(sha256(Buffer.from(baseInput.bodyText, 'utf-8'))); + + const att = result.artifacts.find((a) => a.kind === 'ATTACHMENT'); + expect(att?.sha256).toBe(sha256(Buffer.from(baseInput.attachments[0].bytes))); + expect(att?.fileName).toBe('attachment-1.pdf'); + }); + + it('schreibt body.html nur wenn vorhanden', async () => { + const noHtml = await writeArchive({ ...baseInput, messageIdHash: 'b'.repeat(64) }); + expect(noHtml.artifacts.some((a) => a.kind === 'MAIL_BODY_HTML')).toBe(false); + + const withHtml = await writeArchive({ + ...baseInput, + messageIdHash: 'c'.repeat(64), + bodyHtml: '

Hallo

', + }); + const htmlArtifact = withHtml.artifacts.find((a) => a.kind === 'MAIL_BODY_HTML'); + expect(htmlArtifact?.contentType).toBe('text/html; charset=utf-8'); + expect(htmlArtifact?.sha256).toBe(sha256(Buffer.from('

Hallo

', 'utf-8'))); + }); + + it('ist idempotent — zweiter Aufruf mit gleichem Hash schreibt nichts neues', async () => { + const first = await writeArchive(baseInput); + expect(first.alreadyExisted).toBe(false); + + // Inhalt manipulieren wäre real read-only blockiert; wir checken nur, + // dass der zweite Aufruf NICHT überschreibt und alreadyExisted=true. + const second = await writeArchive(baseInput); + expect(second.alreadyExisted).toBe(true); + expect(second.archivePath).toBe(first.archivePath); + + // Hashes vom Re-Scan sind identisch zum Erst-Write. + const firstEml = first.artifacts.find((a) => a.kind === 'MAIL_EML'); + const secondEml = second.artifacts.find((a) => a.kind === 'MAIL_EML'); + expect(secondEml?.sha256).toBe(firstEml?.sha256); + }); + + it('verweigert unsichere Pfad-Segmente in messageIdHash', async () => { + await expect( + writeArchive({ ...baseInput, messageIdHash: '../etc/passwd' }), + ).rejects.toThrow(); + }); + + it('verweigert messageIdHash, der kein 64-hex ist', async () => { + await expect( + writeArchive({ ...baseInput, messageIdHash: 'xyz' }), + ).rejects.toThrow(/64-stelliger/); + }); + + it('legt mehrere Anhänge nummeriert ab', async () => { + const result = await writeArchive({ + ...baseInput, + messageIdHash: 'd'.repeat(64), + attachments: [ + { + fileName: 'rechnung1.pdf', + contentType: 'application/pdf', + bytes: new Uint8Array(Buffer.from('PDF1')), + }, + { + fileName: 'rechnung2.pdf', + contentType: 'application/pdf', + bytes: new Uint8Array(Buffer.from('PDF2')), + }, + ], + }); + const attachments = result.artifacts.filter((a) => a.kind === 'ATTACHMENT'); + expect(attachments.map((a) => a.fileName).sort()).toEqual([ + 'attachment-1.pdf', + 'attachment-2.pdf', + ]); + }); + + it('Dateien sind nach dem Move read-only (0440)', async () => { + const result = await writeArchive({ ...baseInput, messageIdHash: 'e'.repeat(64) }); + const emlPath = path.join(result.absolutePath, 'mail.eml'); + const stat = await fs.stat(emlPath); + // Mode-Bits maskieren (S_IFMT etc.) und nur Permission-Bits prüfen. + expect(stat.mode & 0o777).toBe(0o440); + }); +}); diff --git a/packages/lib/server-only/sources/archive/archive-writer.ts b/packages/lib/server-only/sources/archive/archive-writer.ts new file mode 100644 index 0000000..b8f1712 --- /dev/null +++ b/packages/lib/server-only/sources/archive/archive-writer.ts @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +import { createHash } from 'node:crypto'; +import { promises as fs } from 'node:fs'; +import path from 'node:path'; + +import { env } from '@nexasign/lib/utils/env'; + +/** + * Schreibt Mail-Artifacts (eml, body, attachments, metadata) atomar und + * idempotent in den Archiv-Ordner. Verwendung von tmp-Verzeichnis + + * `fs.rename` (atomic on POSIX, single-volume) verhindert Halb-Zustände. + * + * Idempotenz: bevor irgendwas geschrieben wird, prüfen wir, ob das Final- + * Verzeichnis schon existiert. Wenn ja → no-op und gespeicherte Hashes + * zurückgeben (read-only re-scan). + * + * GoBD-Härtung: nach erfolgreichem Move wird jede Datei auf 0440 gechmodet, + * Verzeichnisse auf 0550 — Schutz gegen versehentliche lokale Edits. + */ + +const DEFAULT_BASE = '/var/lib/nexasign/sources'; + +const MAIL_EML = 'mail.eml'; +const MAIL_BODY_TEXT = 'body.txt'; +const MAIL_BODY_HTML = 'body.html'; +const MAIL_METADATA = 'metadata.json'; + +const FILE_MODE = 0o440; +const DIR_MODE = 0o550; + +export type ArtifactKind = + | 'MAIL_EML' + | 'MAIL_BODY_TEXT' + | 'MAIL_BODY_HTML' + | 'MAIL_METADATA' + | 'ATTACHMENT'; + +export type ArchiveArtifactRecord = { + kind: ArtifactKind; + fileName: string; + contentType: string; + fileSize: number; + sha256: string; + relativePath: string; // relativ zum DiscoveryDocument-Ordner +}; + +export type ArchiveWriteInput = { + sourceId: string; + /** sha256(messageId), 64 hex chars. */ + messageIdHash: string; + /** Datum zum Sortieren in /-Unterordner. */ + receivedAt: Date; + rawEml: Buffer; + bodyText: string; + bodyHtml: string | null; + metadata: Record; + attachments: Array<{ + fileName: string; + contentType: string; + bytes: Uint8Array; + }>; +}; + +export type ArchiveWriteResult = { + /** Pfad relativ zur Archive-Base, z. B. "src_abc/2024/05/". */ + archivePath: string; + /** Absoluter Pfad — nur für Diagnose. */ + absolutePath: string; + artifacts: ArchiveArtifactRecord[]; + alreadyExisted: boolean; +}; + +const sha256Hex = (buf: Buffer | Uint8Array): string => + createHash('sha256').update(buf).digest('hex'); + +const getArchiveBase = (): string => { + return env('NEXT_PRIVATE_DISCOVERY_ARCHIVE_PATH') ?? DEFAULT_BASE; +}; + +/** + * Sichert, dass ein Pfadbestandteil keine Verzeichnis-Traversal-Pattern enthält. + * messageIdHash sollte 64-hex sein, sourceId ist cuid — beides ungefährlich. + * Diese Funktion ist defensives Härten gegen Programmierfehler beim Aufrufer. + */ +const safeSegment = (s: string): string => { + if (!s || s.includes('/') || s.includes('\\') || s.includes('..') || s.includes('\0')) { + throw new Error(`Unsicheres Pfad-Segment: ${s}`); + } + return s; +}; + +const safeAttachmentName = (raw: string, index: number): string => { + // Anhänge bekommen einen sicheren Namen mit dem Original-Suffix als Hint. + // Original-Filename liegt zusätzlich in metadata.json mit drin. + const ext = path.extname(raw).slice(0, 12).replace(/[^a-z0-9.]/gi, '') || '.bin'; + return `attachment-${index + 1}${ext}`; +}; + +const writeFile = async ( + fullPath: string, + data: Buffer | string, + contentType: string, + kind: ArtifactKind, + fileName: string, + relativePath: string, +): Promise => { + const buf = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data; + await fs.writeFile(fullPath, buf, { mode: FILE_MODE }); + return { + kind, + fileName, + contentType, + fileSize: buf.length, + sha256: sha256Hex(buf), + relativePath, + }; +}; + +const monthSegment = (date: Date): { year: string; month: string } => ({ + year: String(date.getUTCFullYear()), + month: String(date.getUTCMonth() + 1).padStart(2, '0'), +}); + +/** + * Falls ein Archiv-Ordner bereits existiert (weil ein voriger Sync genau + * dieses messageIdHash schon abgelegt hat), lesen wir die Hashes der Dateien + * neu ein und geben sie zurück, statt zu schreiben. Damit ist das gesamte + * Insert idempotent — auch ohne DB-Eintrag (z. B. nach DB-Reset). + */ +const rescanExisting = async ( + absoluteDir: string, + relativeArchivePath: string, +): Promise => { + const entries = await fs.readdir(absoluteDir); + const out: ArchiveArtifactRecord[] = []; + + for (const fileName of entries) { + const fullPath = path.join(absoluteDir, fileName); + const stat = await fs.stat(fullPath); + if (!stat.isFile()) continue; + + const buf = await fs.readFile(fullPath); + const sha256 = sha256Hex(buf); + let kind: ArtifactKind; + let contentType: string; + if (fileName === MAIL_EML) { + kind = 'MAIL_EML'; + contentType = 'message/rfc822'; + } else if (fileName === MAIL_BODY_TEXT) { + kind = 'MAIL_BODY_TEXT'; + contentType = 'text/plain; charset=utf-8'; + } else if (fileName === MAIL_BODY_HTML) { + kind = 'MAIL_BODY_HTML'; + contentType = 'text/html; charset=utf-8'; + } else if (fileName === MAIL_METADATA) { + kind = 'MAIL_METADATA'; + contentType = 'application/json'; + } else if (fileName.startsWith('attachment-')) { + kind = 'ATTACHMENT'; + const ext = path.extname(fileName).toLowerCase(); + contentType = ext === '.pdf' ? 'application/pdf' : 'application/octet-stream'; + } else { + // Unbekannte Datei im Ordner — überspringen, wir kontrollieren das Layout. + continue; + } + + out.push({ + kind, + fileName, + contentType, + fileSize: stat.size, + sha256, + relativePath: fileName, + }); + } + + return out; +}; + +export const writeArchive = async (input: ArchiveWriteInput): Promise => { + const safeSource = safeSegment(input.sourceId); + const safeHash = safeSegment(input.messageIdHash); + if (!/^[a-f0-9]{64}$/.test(safeHash)) { + throw new Error('messageIdHash muss 64-stelliger sha256-Hex-String sein.'); + } + + const { year, month } = monthSegment(input.receivedAt); + const relativeArchivePath = path.join(safeSource, year, month, safeHash); + const base = getArchiveBase(); + const finalDir = path.join(base, relativeArchivePath); + + // Idempotenz: existiert das Final-Verzeichnis schon, dann nichts schreiben. + try { + const stat = await fs.stat(finalDir); + if (stat.isDirectory()) { + const artifacts = await rescanExisting(finalDir, relativeArchivePath); + return { + archivePath: relativeArchivePath, + absolutePath: finalDir, + artifacts, + alreadyExisted: true, + }; + } + } catch (err: unknown) { + if (!(err instanceof Error) || !('code' in err) || err.code !== 'ENOENT') { + throw err; + } + // ENOENT → wir schreiben gleich neu. + } + + // tmp-Verzeichnis im selben Eltern-Pfad, damit `fs.rename` atomar bleibt + // (selbe Volume-Boundary). `.tmp.` reduziert Race auf null. + const parentDir = path.dirname(finalDir); + await fs.mkdir(parentDir, { recursive: true }); + + const tmpSuffix = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; + const tmpDir = path.join(parentDir, `.${safeHash}.tmp.${tmpSuffix}`); + + await fs.mkdir(tmpDir, { recursive: true, mode: 0o700 }); + + try { + const artifacts: ArchiveArtifactRecord[] = []; + + artifacts.push( + await writeFile( + path.join(tmpDir, MAIL_EML), + input.rawEml, + 'message/rfc822', + 'MAIL_EML', + MAIL_EML, + MAIL_EML, + ), + ); + + artifacts.push( + await writeFile( + path.join(tmpDir, MAIL_BODY_TEXT), + input.bodyText, + 'text/plain; charset=utf-8', + 'MAIL_BODY_TEXT', + MAIL_BODY_TEXT, + MAIL_BODY_TEXT, + ), + ); + + if (input.bodyHtml) { + artifacts.push( + await writeFile( + path.join(tmpDir, MAIL_BODY_HTML), + input.bodyHtml, + 'text/html; charset=utf-8', + 'MAIL_BODY_HTML', + MAIL_BODY_HTML, + MAIL_BODY_HTML, + ), + ); + } + + artifacts.push( + await writeFile( + path.join(tmpDir, MAIL_METADATA), + JSON.stringify(input.metadata, null, 2), + 'application/json', + 'MAIL_METADATA', + MAIL_METADATA, + MAIL_METADATA, + ), + ); + + for (let i = 0; i < input.attachments.length; i += 1) { + const att = input.attachments[i]; + const fileName = safeAttachmentName(att.fileName, i); + const buf = Buffer.from(att.bytes); + artifacts.push( + await writeFile( + path.join(tmpDir, fileName), + buf, + att.contentType || 'application/octet-stream', + 'ATTACHMENT', + fileName, + fileName, + ), + ); + } + + // Atomic move tmp → final. Wenn jemand parallel das Final schon angelegt + // hat, gewinnt der Fastest-Writer — wir cleanen unseren tmp-Ordner. + try { + await fs.rename(tmpDir, finalDir); + } catch (err: unknown) { + // EEXIST/ENOTEMPTY: paralleler Schreiber kam zuerst → no-op. + if ( + err instanceof Error && + 'code' in err && + (err.code === 'EEXIST' || err.code === 'ENOTEMPTY') + ) { + await fs.rm(tmpDir, { recursive: true, force: true }); + const existingArtifacts = await rescanExisting(finalDir, relativeArchivePath); + return { + archivePath: relativeArchivePath, + absolutePath: finalDir, + artifacts: existingArtifacts, + alreadyExisted: true, + }; + } + throw err; + } + + // Verzeichnis read-only setzen. + await fs.chmod(finalDir, DIR_MODE); + + return { + archivePath: relativeArchivePath, + absolutePath: finalDir, + artifacts, + alreadyExisted: false, + }; + } catch (err) { + // Bei Fehler tmp aufräumen, damit kein Müll bleibt. + await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {}); + throw err; + } +}; + +export const getAbsoluteArchivePath = (archivePath: string): string => { + return path.join(getArchiveBase(), archivePath); +}; diff --git a/packages/lib/server-only/sources/archive/index.ts b/packages/lib/server-only/sources/archive/index.ts new file mode 100644 index 0000000..7ef8569 --- /dev/null +++ b/packages/lib/server-only/sources/archive/index.ts @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +export { writeArchive, getAbsoluteArchivePath } from './archive-writer'; +export type { + ArchiveArtifactRecord, + ArchiveWriteInput, + ArchiveWriteResult, + ArtifactKind, +} from './archive-writer'; diff --git a/packages/lib/server-only/sources/imap/classifier.test.ts b/packages/lib/server-only/sources/imap/classifier.test.ts new file mode 100644 index 0000000..3e5b818 --- /dev/null +++ b/packages/lib/server-only/sources/imap/classifier.test.ts @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +import { describe, expect, it } from 'vitest'; + +import { classifyAndExtract, classifyMail, extractAmount, extractInvoiceNumber } from './classifier'; + +describe('classifyMail', () => { + it('AUTO bei bekanntem Beleg-Sender mit PDF', () => { + expect( + classifyMail({ + senderDomain: 'hetzner.com', + subject: 'Ihre Rechnung', + bodyText: 'Anbei Rechnung', + hasPdfAttachment: true, + }), + ).toBe('AUTO'); + }); + + it('AUTO bei unbekanntem Sender mit Beleg-Keyword + PDF', () => { + expect( + classifyMail({ + senderDomain: 'unbekannt.de', + subject: 'Rechnung Nr 12345', + bodyText: 'Anbei', + hasPdfAttachment: true, + }), + ).toBe('AUTO'); + }); + + it('MANUAL bei Beleg-Hinweis ohne PDF', () => { + expect( + classifyMail({ + senderDomain: 'telekom.de', + subject: 'Ihre Rechnung steht im Kundenportal bereit', + bodyText: 'Bitte einloggen', + hasPdfAttachment: false, + }), + ).toBe('MANUAL'); + }); + + it('IGNORE bei reiner Werbung', () => { + expect( + classifyMail({ + senderDomain: 'newsletter.de', + subject: 'Sale 50% off', + bodyText: 'Jetzt zugreifen!', + hasPdfAttachment: false, + }), + ).toBe('IGNORE'); + }); + + it('Bekannter Sender überstimmt Werbe-Keyword', () => { + expect( + classifyMail({ + senderDomain: 'amazon.de', + subject: 'Ihre Rechnung — 20% Rabatt im nächsten Einkauf', + bodyText: '', + hasPdfAttachment: true, + }), + ).toBe('AUTO'); + }); + + it('Subdomain bekannter Sender wird erkannt', () => { + expect( + classifyMail({ + senderDomain: 'noreply.stripe.com', + subject: 'Receipt', + bodyText: '', + hasPdfAttachment: true, + }), + ).toBe('AUTO'); + }); +}); + +describe('extractAmount', () => { + it('erkennt EUR-Beträge mit Dezimalkomma', () => { + expect(extractAmount('Gesamt: 19,99 EUR')).toBe('19,99 EUR'); + }); + + it('erkennt USD-Beträge mit $ vorne', () => { + expect(extractAmount('Total: $1,234.56')).toBe('1,234.56 USD'); + }); + + it('erkennt Euro-Symbol vor Betrag', () => { + expect(extractAmount('€ 99,00')).toBe('99,00 EUR'); + }); + + it('null wenn nichts matched', () => { + expect(extractAmount('Hallo Welt')).toBe(null); + }); +}); + +describe('extractInvoiceNumber', () => { + it('erkennt Rechnungs-Nr', () => { + expect(extractInvoiceNumber('Rechnungs-Nr: ABC-12345')).toBe('ABC-12345'); + }); + + it('erkennt Invoice no', () => { + expect(extractInvoiceNumber('Invoice no INV/2024/789')).toBe('INV/2024/789'); + }); + + it('null wenn nichts matched', () => { + expect(extractInvoiceNumber('Hallo Welt')).toBe(null); + }); +}); + +describe('classifyAndExtract', () => { + it('extrahiert keine Felder bei IGNORE', () => { + const result = classifyAndExtract({ + senderDomain: 'spam.com', + subject: 'Tolle Angebote', + bodyText: 'sale 99,99 EUR', + hasPdfAttachment: false, + }); + expect(result.verdict).toBe('IGNORE'); + expect(result.detectedAmount).toBe(null); + expect(result.detectedInvoiceNumber).toBe(null); + }); + + it('extrahiert strukturierte Felder bei AUTO', () => { + const result = classifyAndExtract({ + senderDomain: 'hetzner.com', + subject: 'Rechnung R-2024-001', + bodyText: 'Gesamtbetrag: 49,90 EUR. Rechnungs-Nr: R-2024-001', + hasPdfAttachment: true, + }); + expect(result.verdict).toBe('AUTO'); + expect(result.detectedAmount).toBe('49,90 EUR'); + expect(result.detectedInvoiceNumber).toBe('R-2024-001'); + }); + + it('extrahiert portalHint nur bei MANUAL', () => { + const result = classifyAndExtract({ + senderDomain: 'telekom.de', + subject: 'Rechnung verfügbar', + bodyText: 'Bitte einloggen unter mein-portal.de', + hasPdfAttachment: false, + }); + expect(result.verdict).toBe('MANUAL'); + expect(result.portalHint).toContain('einloggen unter'); + }); +}); diff --git a/packages/lib/server-only/sources/imap/classifier.ts b/packages/lib/server-only/sources/imap/classifier.ts new file mode 100644 index 0000000..2a58f5b --- /dev/null +++ b/packages/lib/server-only/sources/imap/classifier.ts @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { + IGNORE_KEYWORDS, + KNOWN_RECHNUNG_DOMAINS, + PORTAL_HINTS, + RECHNUNG_KEYWORDS, +} from './keywords'; + +export type ClassificationVerdict = 'AUTO' | 'MANUAL' | 'IGNORE'; + +export type MailFeatures = { + senderDomain: string; + subject: string; + bodyText: string; + hasPdfAttachment: boolean; +}; + +export type ClassificationResult = { + verdict: ClassificationVerdict; + detectedAmount: string | null; + detectedInvoiceNumber: string | null; + portalHint: string | null; +}; + +const containsAny = (haystack: string, needles: ReadonlyArray): boolean => { + const low = haystack.toLowerCase(); + return needles.some((needle) => low.includes(needle)); +}; + +const isKnownSender = (senderDomain: string): boolean => { + const lower = senderDomain.toLowerCase(); + return KNOWN_RECHNUNG_DOMAINS.some((known) => lower === known || lower.endsWith(`.${known}`)); +}; + +/** + * Beleg-Klassifizierung — Port aus rechnungen.py:classify(). + * + * AUTO = Beleg-Hinweis erkannt UND PDF im Anhang. + * MANUAL = Beleg-Hinweis erkannt, aber kein PDF (User muss aus Portal ziehen). + * IGNORE = Werbung / Newsletter / nicht-Beleg. + */ +export const classifyMail = (features: MailFeatures): ClassificationVerdict => { + const haystack = `${features.subject}\n${features.bodyText}`; + + const knownSender = isKnownSender(features.senderDomain); + const hasRechnungKeyword = containsAny(haystack, RECHNUNG_KEYWORDS); + const hasIgnoreKeyword = containsAny(haystack, IGNORE_KEYWORDS); + + // Bekannter Absender ODER Beleg-Keyword reicht als Vor-Treffer. + const isRechnungsmail = knownSender || hasRechnungKeyword; + + if (!isRechnungsmail) { + return 'IGNORE'; + } + // Werbung mit Beleg-Keyword (z.B. „Rabatt-Newsletter") aussortieren. + // Bekannte Beleg-Sender überstimmen das. + if (hasIgnoreKeyword && !knownSender) { + return 'IGNORE'; + } + if (features.hasPdfAttachment) { + return 'AUTO'; + } + return 'MANUAL'; +}; + +// Erkennt sowohl „12,99 €" / „12.99 EUR" als auch „$12.99" / „USD 12.99". +const AMOUNT_RX = + /(?:(?€|EUR|USD|\$)\s*(?\d{1,3}(?:[.,\s]\d{3})*[.,]\d{2}))|(?:(?\d{1,3}(?:[.,\s]\d{3})*[.,]\d{2})\s*(?€|EUR|USD|\$))/i; + +const INVOICE_NR_RX = + /(?:rechnungs?\s*-?\s*nr\.?|invoice\s*(?:no|number|#)|beleg\s*nr\.?|order\s*#?|auftrag\s*#?)\s*[:#]?\s*(?[A-Z0-9][A-Z0-9\-_/]{3,30})/i; + +const normalizeCurrency = (cur: string): string => { + const upper = cur.toUpperCase(); + if (upper === '$') return 'USD'; + if (upper === '€') return 'EUR'; + return upper; +}; + +export const extractAmount = (text: string): string | null => { + const match = AMOUNT_RX.exec(text); + if (!match || !match.groups) return null; + const num = match.groups.num1 ?? match.groups.num2; + const cur = match.groups.cur1 ?? match.groups.cur2; + if (!num || !cur) return null; + return `${num} ${normalizeCurrency(cur)}`.trim(); +}; + +export const extractInvoiceNumber = (text: string): string | null => { + const match = INVOICE_NR_RX.exec(text); + return match?.groups?.nr ?? null; +}; + +export const detectPortalHint = (text: string): string | null => { + const low = text.toLowerCase(); + for (const hint of PORTAL_HINTS) { + if (low.includes(hint)) return hint; + } + return null; +}; + +/** + * Komplett-Klassifizierung inkl. strukturierter Felder. Body-Text wird hier + * ein letztes Mal benutzt — nach diesem Aufruf wird er verworfen, nichts geht + * an die DB außer den vier Rückgabe-Feldern. + */ +export const classifyAndExtract = (features: MailFeatures): ClassificationResult => { + const verdict = classifyMail(features); + if (verdict === 'IGNORE') { + return { + verdict, + detectedAmount: null, + detectedInvoiceNumber: null, + portalHint: null, + }; + } + const haystack = `${features.subject}\n${features.bodyText}`; + return { + verdict, + detectedAmount: extractAmount(haystack), + detectedInvoiceNumber: extractInvoiceNumber(haystack), + portalHint: verdict === 'MANUAL' ? detectPortalHint(haystack) : null, + }; +}; diff --git a/packages/lib/server-only/sources/imap/extract.test.ts b/packages/lib/server-only/sources/imap/extract.test.ts new file mode 100644 index 0000000..f671b33 --- /dev/null +++ b/packages/lib/server-only/sources/imap/extract.test.ts @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +import { describe, expect, it } from 'vitest'; + +import { parseRawMail } from './extract'; + +const buildRfc822Mail = (parts: { + subject?: string; + text?: string; + html?: string; + from?: string; + date?: string; +}): Buffer => { + const headers = [ + `From: ${parts.from ?? 'sender@example.com'}`, + `Subject: ${parts.subject ?? 'Test'}`, + `Date: ${parts.date ?? 'Mon, 1 Jan 2024 10:00:00 +0000'}`, + 'Message-ID: ', + 'MIME-Version: 1.0', + ]; + + if (parts.html && parts.text) { + const boundary = 'BOUNDARY42'; + return Buffer.from( + [ + ...headers, + `Content-Type: multipart/alternative; boundary="${boundary}"`, + '', + `--${boundary}`, + 'Content-Type: text/plain; charset=utf-8', + '', + parts.text, + `--${boundary}`, + 'Content-Type: text/html; charset=utf-8', + '', + parts.html, + `--${boundary}--`, + '', + ].join('\r\n'), + ); + } + + if (parts.html) { + return Buffer.from( + [...headers, 'Content-Type: text/html; charset=utf-8', '', parts.html].join('\r\n'), + ); + } + + return Buffer.from( + [...headers, 'Content-Type: text/plain; charset=utf-8', '', parts.text ?? ''].join('\r\n'), + ); +}; + +describe('parseRawMail body handling', () => { + it('liefert text/plain als bodyText, kein bodyHtml', async () => { + const raw = buildRfc822Mail({ text: 'Hallo Welt' }); + const parsed = await parseRawMail(raw); + expect(parsed.bodyText).toContain('Hallo Welt'); + expect(parsed.bodyHtml).toBe(null); + }); + + it('strippt HTML aus bodyText, behält bodyHtml für Datei-Ablage', async () => { + const raw = buildRfc822Mail({ html: '

Hallo Welt

' }); + const parsed = await parseRawMail(raw); + expect(parsed.bodyHtml).toContain('

'); + // bodyText hat das HTML gestripped — keine Tags, kein "<". + expect(parsed.bodyText).not.toContain('<'); + expect(parsed.bodyText).not.toContain('>'); + expect(parsed.bodyText).toContain('Hallo'); + }); + + it('script/javascript-Inhalte landen NICHT im bodyText (nur in bodyHtml-Datei)', async () => { + const raw = buildRfc822Mail({ + html: 'click', + }); + const parsed = await parseRawMail(raw); + // bodyText ist HTML-stripped — keine Tags durch. + expect(parsed.bodyText).not.toContain(' { + const raw = buildRfc822Mail({ + text: 'Klartext-Variante', + html: '

HTML-Variante

', + }); + const parsed = await parseRawMail(raw); + expect(parsed.bodyText).toContain('Klartext-Variante'); + expect(parsed.bodyHtml).toContain('HTML-Variante'); + }); + + it('bodyText wird auf 1 MB gekürzt', async () => { + const big = 'x'.repeat(1_500_000); + const raw = buildRfc822Mail({ text: big }); + const parsed = await parseRawMail(raw); + const bytes = Buffer.byteLength(parsed.bodyText, 'utf-8'); + expect(bytes).toBeLessThanOrEqual(1024 * 1024 + 200); + expect(parsed.bodyText).toMatch(/gekürzt/); + }); +}); diff --git a/packages/lib/server-only/sources/imap/extract.ts b/packages/lib/server-only/sources/imap/extract.ts new file mode 100644 index 0000000..cc28dbd --- /dev/null +++ b/packages/lib/server-only/sources/imap/extract.ts @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { type Attachment, simpleParser } from 'mailparser'; + +/** + * Mail-Parsing + PDF-Anhang-Extraktion. + * + * Logik portiert aus rechnungen.py: + * - text/plain bevorzugt, HTML-Fallback mit Tag-Strip + * - PDF-Anhänge direkt + * - PDF-Dateien innerhalb von ZIP-Attachments mit ausgepackt + */ + +export type ExtractedAttachment = { + fileName: string; + contentType: string; + bytes: Uint8Array; + fromZip: boolean; +}; + +export type ParsedMail = { + subject: string; + fromName: string; + fromAddress: string; + fromDomain: string; + date: Date; + /** Klartext-Body, max 1 MB. UI-Anzeige & DiscoveryDocument.bodyText. */ + bodyText: string; + /** Roh-HTML-Body (falls vorhanden) — wird NUR als Datei abgelegt, nie inline gerendert. */ + bodyHtml: string | null; + messageId: string; + pdfAttachments: ExtractedAttachment[]; +}; + +/** + * Hard-Limit für `bodyText`: alles über 1 MB wird abgeschnitten + Marker. + * Begründung: DB-Spalte ist TEXT (unbegrenzt), aber wir wollen nicht ein + * 50-MB-HTML-Newsletter in jeder Listenansicht laden. Das vollständige + * Original liegt eh in der `.eml`/`body.html`-Datei. + */ +const MAX_BODY_TEXT_BYTES = 1024 * 1024; +const truncateBody = (text: string): string => { + const buf = Buffer.from(text, 'utf-8'); + if (buf.length <= MAX_BODY_TEXT_BYTES) return text; + // Auf Byte-Grenze schneiden, ohne UTF-8-Multibyte mittendrin zu zerhacken. + const cut = buf.subarray(0, MAX_BODY_TEXT_BYTES).toString('utf-8'); + return `${cut}\n\n[…gekürzt — vollständiger Inhalt in mail.eml]`; +}; + +const stripHtml = (html: string): string => + html + .replace(/<[^>]+>/g, ' ') + .replace(/\s+/g, ' ') + .trim(); + +const isPdfAttachment = (att: Attachment): boolean => { + if (att.contentType?.toLowerCase() === 'application/pdf') return true; + return Boolean(att.filename && att.filename.toLowerCase().endsWith('.pdf')); +}; + +const isZipAttachment = (att: Attachment): boolean => { + const ct = att.contentType?.toLowerCase(); + if (ct === 'application/zip' || ct === 'application/x-zip-compressed') return true; + return Boolean(att.filename && att.filename.toLowerCase().endsWith('.zip')); +}; + +const extractPdfsFromZip = async ( + blob: Buffer, + _parentName: string, +): Promise => { + // Lazy-import, damit jszip nur lädt, wenn ein ZIP wirklich vorkommt. + const { default: JSZip } = await import('jszip'); + const out: ExtractedAttachment[] = []; + try { + const zip = await JSZip.loadAsync(blob); + for (const [name, entry] of Object.entries(zip.files)) { + if (entry.dir) continue; + if (!name.toLowerCase().endsWith('.pdf')) continue; + const data = await entry.async('uint8array'); + const baseName = name.split('/').pop() ?? name; + out.push({ + fileName: baseName, + contentType: 'application/pdf', + bytes: data, + fromZip: true, + }); + } + } catch { + // Defektes ZIP überspringen — kein Hard-Fail. + return []; + } + return out; +}; + +const domainFromAddress = (addr: string): string => { + const at = addr.indexOf('@'); + return at >= 0 ? addr.slice(at + 1).toLowerCase() : ''; +}; + +export const parseRawMail = async (raw: Buffer): Promise => { + const parsed = await simpleParser(raw); + + const text = parsed.text ?? (parsed.html ? stripHtml(parsed.html) : ''); + + const fromEntry = Array.isArray(parsed.from) ? parsed.from[0] : parsed.from; + const fromValue = fromEntry?.value?.[0]; + const fromAddress = (fromValue?.address ?? '').toLowerCase(); + const fromName = fromValue?.name ?? ''; + + const pdfAttachments: ExtractedAttachment[] = []; + + for (const att of parsed.attachments ?? []) { + if (!att.content) continue; + const buf = Buffer.isBuffer(att.content) ? att.content : Buffer.from(att.content); + if (isPdfAttachment(att)) { + pdfAttachments.push({ + fileName: att.filename ?? 'beleg.pdf', + contentType: att.contentType ?? 'application/pdf', + bytes: new Uint8Array(buf), + fromZip: false, + }); + } else if (isZipAttachment(att)) { + const inner = await extractPdfsFromZip(buf, att.filename ?? 'archive.zip'); + pdfAttachments.push(...inner); + } + } + + return { + subject: parsed.subject ?? '', + fromName, + fromAddress, + fromDomain: domainFromAddress(fromAddress), + date: parsed.date ?? new Date(), + bodyText: truncateBody(text), + bodyHtml: parsed.html ? parsed.html : null, + messageId: parsed.messageId ?? '', + pdfAttachments, + }; +}; diff --git a/packages/lib/server-only/sources/imap/host-allowlist.ts b/packages/lib/server-only/sources/imap/host-allowlist.ts new file mode 100644 index 0000000..3d0a4bf --- /dev/null +++ b/packages/lib/server-only/sources/imap/host-allowlist.ts @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { promises as dns } from 'node:dns'; + +import { env } from '@nexasign/lib/utils/env'; + +/** + * SSRF-Schutz für die User-eingegebene IMAP-Host-Adresse. + * + * Default: harte Allowlist von Mainstream-Providern. Power-User können via + * `NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS=true` eigene Hosts erlauben — dann + * wird der Host per DNS aufgelöst und gegen private/loopback/Tailscale-Ranges + * geprüft. + * + * Port: nur 993 (IMAPS) und 143 (STARTTLS) erlaubt. + */ + +const DEFAULT_ALLOWLIST: ReadonlyArray = [ + 'imap.gmail.com', + 'outlook.office365.com', + 'imap.fastmail.com', + 'secureimap.t-online.de', + 'imap.web.de', + 'imap.gmx.net', + 'imap.gmx.de', + 'imap.mail.me.com', + 'imap.mail.yahoo.com', + 'mailbox.org', + 'imap.posteo.de', +]; + +const ALLOWED_PORTS = new Set([993, 143]); + +/** + * Liest die effektive Allowlist aus Env (`NEXT_PRIVATE_IMAP_HOST_ALLOWLIST`, + * komma-getrennt) und mergt mit den Defaults. Default-Liste bleibt immer dabei + * — User-Erweiterung kommt obendrauf. + */ +const readAllowlist = (): Set => { + const raw = env('NEXT_PRIVATE_IMAP_HOST_ALLOWLIST'); + const extra = raw + ? raw + .split(',') + .map((s) => s.trim().toLowerCase()) + .filter(Boolean) + : []; + return new Set([...DEFAULT_ALLOWLIST.map((h) => h.toLowerCase()), ...extra]); +}; + +const customHostsAllowed = (): boolean => { + return env('NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS') === 'true'; +}; + +export type HostValidationResult = { + ok: boolean; + reason?: string; +}; + +const isPrivateIPv4 = (ip: string): boolean => { + const parts = ip.split('.').map((n) => parseInt(n, 10)); + if (parts.length !== 4 || parts.some((n) => Number.isNaN(n) || n < 0 || n > 255)) { + return false; + } + const [a, b] = parts; + // RFC1918 + if (a === 10) return true; + if (a === 172 && b >= 16 && b <= 31) return true; + if (a === 192 && b === 168) return true; + // Loopback + if (a === 127) return true; + // Link-local + if (a === 169 && b === 254) return true; + // CGNAT (RFC6598) — auch von Tailscale genutzt (100.64.0.0/10). + if (a === 100 && b >= 64 && b <= 127) return true; + // Multicast / reserved + if (a >= 224) return true; + // Broadcast + if (a === 255) return true; + // 0.0.0.0/8 — „this network", nicht routbar. + if (a === 0) return true; + return false; +}; + +const isPrivateIPv6 = (ip: string): boolean => { + const lower = ip.toLowerCase(); + // Loopback + if (lower === '::1') return true; + // Unspecified + if (lower === '::') return true; + // Link-local fe80::/10 + if ( + lower.startsWith('fe80:') || + lower.startsWith('fe8') || + lower.startsWith('fe9') || + lower.startsWith('fea') || + lower.startsWith('feb') + ) { + return true; + } + // Unique local fc00::/7 + if (lower.startsWith('fc') || lower.startsWith('fd')) return true; + // IPv4-mapped (::ffff:a.b.c.d) — auf v4-Logik abbilden + const v4MappedMatch = lower.match(/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/); + if (v4MappedMatch) { + return isPrivateIPv4(v4MappedMatch[1]); + } + // Multicast ff00::/8 + if (lower.startsWith('ff')) return true; + return false; +}; + +const isPrivateAddress = (ip: string): boolean => { + if (ip.includes(':')) return isPrivateIPv6(ip); + return isPrivateIPv4(ip); +}; + +const isIpLiteral = (host: string): boolean => /^[\d.]+$/.test(host) || host.includes(':'); + +/** + * Prüft Host + Port. Bei Custom-Host-Zulassung wird DNS aufgelöst und gegen + * private Ranges geprüft. Bei IP-Literal als Host wird sofort die Range-Prüfung + * angewendet (ohne DNS-Round-Trip). + */ +export const validateImapHost = async ( + host: string, + port: number, +): Promise => { + if (!ALLOWED_PORTS.has(port)) { + return { + ok: false, + reason: `Port ${port} nicht erlaubt — nur 993 (IMAPS) oder 143 (STARTTLS).`, + }; + } + + const normalized = host.trim().toLowerCase(); + if (!normalized) { + return { ok: false, reason: 'Host darf nicht leer sein.' }; + } + + // Mainstream-Provider: keine DNS-Auflösung nötig, Allowlist matcht direkt. + const allowlist = readAllowlist(); + if (allowlist.has(normalized)) { + return { ok: true }; + } + + // Custom-Hosts nur, wenn explizit per Env erlaubt. + if (!customHostsAllowed()) { + return { + ok: false, + reason: + 'Eigene IMAP-Hosts sind nicht freigeschaltet. Bitte einen der unterstützten Anbieter auswählen oder den Betreiber bitten, NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS zu aktivieren.', + }; + } + + // IP-Literal: direkt prüfen, kein DNS-Round-Trip. + if (isIpLiteral(normalized)) { + if (isPrivateAddress(normalized)) { + return { + ok: false, + reason: 'Ziel-Adresse liegt in einem privaten oder reservierten Bereich.', + }; + } + return { ok: true }; + } + + // Hostname: DNS-Auflösung gegen private Ranges prüfen. + let addresses: string[] = []; + try { + const lookup = await dns.lookup(normalized, { all: true }); + addresses = lookup.map((entry) => entry.address); + } catch (err) { + return { + ok: false, + reason: `Host ${normalized} ist per DNS nicht auflösbar.`, + }; + } + + if (addresses.length === 0) { + return { ok: false, reason: `Host ${normalized} liefert keine IP-Adressen.` }; + } + + for (const addr of addresses) { + if (isPrivateAddress(addr)) { + return { + ok: false, + reason: `Host ${normalized} löst auf eine private/reservierte Adresse auf (${addr}).`, + }; + } + } + + return { ok: true }; +}; + +/** + * Liefert die Liste der ohne Custom-Host-Freigabe verwendbaren Mainstream- + * Provider. Wird vom UI für Auswahl-Dropdown genutzt. + */ +export const getDefaultImapHostAllowlist = (): ReadonlyArray => { + return [...DEFAULT_ALLOWLIST]; +}; + +export const isCustomImapHostsAllowed = customHostsAllowed; diff --git a/packages/lib/server-only/sources/imap/imap-credentials.ts b/packages/lib/server-only/sources/imap/imap-credentials.ts new file mode 100644 index 0000000..4acb5e6 --- /dev/null +++ b/packages/lib/server-only/sources/imap/imap-credentials.ts @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { symmetricDecrypt, symmetricEncrypt } from '@nexasign/lib/universal/crypto'; +import { env } from '@nexasign/lib/utils/env'; + +import { type ImapAccountConfig, ZImapAccountConfigSchema } from './types'; + +/** + * IMAP-Credential-Encryption — eigener Key (`NEXT_PRIVATE_IMAP_CREDENTIAL_KEY`), + * damit IMAP-Passwörter / OAuth-Refresh-Tokens unabhängig von anderen NexaFile- + * Secrets rotiert werden können. Fallback-Kette für gestaffelte Migration: + * primär `NEXT_PRIVATE_IMAP_CREDENTIAL_KEY`, sekundär das Secondary-Key + * (Vermeidung eines harten Bruchs bei Bestandsinstallationen, die noch keinen + * eigenen IMAP-Key gesetzt haben). + * + * keyVersion-Tracking: jeder Ciphertext landet zusammen mit `keyVersion` in der + * DB. Aktuell nur `"v1"`. Bei Rotation: neue Records bekommen `"v2"`, alte + * werden mit `"v1"`-Schlüssel weiter entschlüsselt, bis ein Re-Encrypt-Job sie + * migriert. + */ + +export const CURRENT_KEY_VERSION = 'v1'; + +const getCurrentKey = (): string => { + const imapKey = env('NEXT_PRIVATE_IMAP_CREDENTIAL_KEY'); + if (imapKey && imapKey.length >= 32) { + return imapKey; + } + + const fallback = env('NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY'); + if (fallback && fallback.length >= 32) { + return fallback; + } + + throw new Error( + 'IMAP-Credential-Verschlüsselung nicht möglich: weder NEXT_PRIVATE_IMAP_CREDENTIAL_KEY ' + + 'noch NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY ist gesetzt (oder beide < 32 Zeichen).', + ); +}; + +const getKeyForVersion = (keyVersion: string): string => { + if (keyVersion === CURRENT_KEY_VERSION) { + return getCurrentKey(); + } + throw new Error(`Unbekannte IMAP-Credential-Key-Version: ${keyVersion}`); +}; + +export type EncryptedImapConfig = { + ciphertext: string; + keyVersion: string; +}; + +export const encryptImapConfig = (config: ImapAccountConfig): EncryptedImapConfig => { + ZImapAccountConfigSchema.parse(config); + + const key = getCurrentKey(); + const ciphertext = symmetricEncrypt({ + key, + data: JSON.stringify(config), + }); + + return { + ciphertext, + keyVersion: CURRENT_KEY_VERSION, + }; +}; + +export const decryptImapConfig = (input: EncryptedImapConfig): ImapAccountConfig => { + const key = getKeyForVersion(input.keyVersion); + const bytes = symmetricDecrypt({ key, data: input.ciphertext }); + const json = new TextDecoder('utf-8').decode(bytes); + const parsed = JSON.parse(json); + return ZImapAccountConfigSchema.parse(parsed); +}; diff --git a/packages/lib/server-only/sources/imap/imap-resync-single.ts b/packages/lib/server-only/sources/imap/imap-resync-single.ts new file mode 100644 index 0000000..5c1e675 --- /dev/null +++ b/packages/lib/server-only/sources/imap/imap-resync-single.ts @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +// +// Re-Sync einer einzelnen DiscoveryDocument-Zeile aus IMAP. +// +// Use-Case: Belege, die importiert wurden BEVOR das Archive-Feature aktiv +// war (vor Commit e6dbf33), haben kein archivePath und keine Artifacts — +// die Mail-Bytes sind nirgends auf dem Server. Diese Funktion zieht die +// Mail nochmal aus IMAP, schreibt das Archive (eml + body + metadata + +// attachments) und ergaenzt den vorhandenen Datensatz mit archivePath + +// DiscoveryArtifact-Zeilen. KEIN neuer DiscoveryDocument-Insert — die +// User-Akzeptanz/Akten-Status etc. bleiben erhalten. +import { ImapFlow } from 'imapflow'; + +import { prisma } from '@nexasign/prisma'; + +import { writeArchive } from '../archive'; +import { parseRawMail } from './extract'; +import { validateImapHost } from './host-allowlist'; +import { decryptImapConfig } from './imap-credentials'; +import { type ImapAccountConfig, ZImapAccountConfigSchema } from './types'; + +const CONNECT_TIMEOUT_MS = 10_000; +const GREETING_TIMEOUT_MS = 30_000; + +const PREFERRED_MAILBOXES = ['[Gmail]/Alle Nachrichten', '[Gmail]/All Mail', 'INBOX']; + +const buildClient = (config: ImapAccountConfig): ImapFlow => + new ImapFlow({ + host: config.host, + port: config.port, + secure: config.port === 993, + auth: { user: config.username, pass: config.password }, + tls: { rejectUnauthorized: config.tlsVerify }, + logger: false, + emitLogs: false, + connectionTimeout: CONNECT_TIMEOUT_MS, + greetingTimeout: GREETING_TIMEOUT_MS, + socketTimeout: GREETING_TIMEOUT_MS, + }); + +const pickMailbox = async (client: ImapFlow): Promise => { + const list = await client.list(); + const known = new Set(list.map((entry) => entry.path)); + for (const candidate of PREFERRED_MAILBOXES) { + if (known.has(candidate)) return candidate; + } + return null; +}; + +export type ResyncSingleResult = + | { ok: true; archivePath: string; attachmentsAdded: number; alreadyHadArchive: boolean } + | { ok: false; reason: string }; + +export type ResyncSingleInput = { + documentId: string; + /** Akteur — nur er darf Belege seines Teams nachladen. */ + userId: number; + teamId: number; +}; + +/** + * Laedt eine einzelne Mail aus IMAP nach. Idempotent — wenn das Archive auf + * Disk schon existiert (gleiche messageIdHash), wird nichts neu geschrieben, + * aber die DiscoveryArtifact-Zeilen werden trotzdem ergaenzt, falls fehlend. + */ +export const resyncSingleDocument = async ( + input: ResyncSingleInput, +): Promise => { + // 1) Document + Source laden, Authorization checken. + const doc = await prisma.discoveryDocument.findFirst({ + where: { + id: input.documentId, + teamId: input.teamId, + uploadedById: input.userId, + providerSource: 'imap', + }, + select: { + id: true, + sourceId: true, + messageIdHash: true, + providerNativeId: true, + documentDate: true, + capturedAt: true, + archivePath: true, + title: true, + correspondent: true, + _count: { select: { artifacts: true } }, + }, + }); + + if (!doc) { + return { ok: false, reason: 'Document nicht gefunden oder keine Berechtigung.' }; + } + if (!doc.sourceId) { + return { ok: false, reason: 'Document hat keine zugeordnete Source — kein Re-Sync möglich.' }; + } + if (!doc.messageIdHash) { + return { ok: false, reason: 'Document hat keinen messageIdHash — IMAP-Bezug verloren.' }; + } + if (!doc.providerNativeId) { + return { ok: false, reason: 'Document hat keine IMAP-UID — IMAP-Bezug verloren.' }; + } + + const source = await prisma.source.findFirst({ + where: { id: doc.sourceId, teamId: input.teamId }, + }); + if (!source) { + return { ok: false, reason: 'Source nicht gefunden oder gelöscht.' }; + } + if (source.lastSyncStatus === 'SUSPENDED') { + return { ok: false, reason: 'Source ist gesperrt — bitte Quelle prüfen.' }; + } + + // 2) Konfig entschluesseln, Host-Allowlist validieren. + let config: ImapAccountConfig; + try { + const decrypted = decryptImapConfig({ + ciphertext: source.encryptedConfig, + keyVersion: source.encryptedConfigKeyVersion, + }); + config = ZImapAccountConfigSchema.parse(decrypted); + } catch (err) { + return { + ok: false, + reason: `Source-Konfig konnte nicht entschlüsselt werden: ${err instanceof Error ? err.message : 'unbekannt'}`, + }; + } + + const hostCheck = await validateImapHost(config.host, config.port); + if (!hostCheck.ok) { + return { ok: false, reason: hostCheck.reason ?? 'Host nicht erlaubt.' }; + } + + // 3) IMAP verbinden, Mail per UID holen. + const client = buildClient(config); + let raw: Buffer | null = null; + + try { + await client.connect(); + const mailbox = await pickMailbox(client); + if (!mailbox) { + return { ok: false, reason: 'Keine kompatible Mailbox gefunden.' }; + } + const lock = await client.getMailboxLock(mailbox); + try { + const uid = doc.providerNativeId; + const message = await client.fetchOne(uid, { source: true }, { uid: true }); + if (!message || !message.source) { + return { + ok: false, + reason: `Mail mit UID ${uid} nicht mehr in der Mailbox — ggf. verschoben oder gelöscht. Bitte einen vollen Sync starten.`, + }; + } + raw = Buffer.isBuffer(message.source) ? message.source : Buffer.from(message.source); + } finally { + lock.release(); + } + } catch (err) { + return { + ok: false, + reason: `IMAP-Fehler: ${err instanceof Error ? err.message : 'unbekannt'}`, + }; + } finally { + if (client.usable) { + try { + await client.logout(); + } catch { + /* ignore */ + } + } + } + + if (!raw) { + return { ok: false, reason: 'Keine Mail-Bytes geholt.' }; + } + + // 4) Mail parsen + Archive schreiben (idempotent). + const parsed = await parseRawMail(raw); + if (!parsed.messageId) { + return { ok: false, reason: 'Mail hat keinen Message-Id-Header.' }; + } + + // Sicherheits-Check: gehoert die geholte Mail zum erwarteten Document? + // Sonst koennte eine UID-Kollision (nach mailbox-Reorganisation) eine fremde + // Mail fuer den User akzeptiert ueberschreiben. + const { createHash } = await import('node:crypto'); + const fetchedHash = createHash('sha256').update(parsed.messageId).digest('hex'); + if (fetchedHash !== doc.messageIdHash) { + return { + ok: false, + reason: `UID ${doc.providerNativeId} verweist jetzt auf eine andere Mail. Mailbox wurde umorganisiert — bitte vollen Sync starten.`, + }; + } + + const archive = await writeArchive({ + sourceId: doc.sourceId, + messageIdHash: doc.messageIdHash, + receivedAt: parsed.date, + rawEml: raw, + bodyText: parsed.bodyText, + bodyHtml: parsed.bodyHtml, + metadata: { + sourceId: doc.sourceId, + messageIdHash: doc.messageIdHash, + messageId: parsed.messageId, + fromName: parsed.fromName, + fromAddress: parsed.fromAddress, + fromDomain: parsed.fromDomain, + subject: parsed.subject, + date: parsed.date.toISOString(), + providerSource: 'imap', + providerNativeId: doc.providerNativeId, + attachmentsOriginalNames: parsed.pdfAttachments.map((a) => a.fileName), + resyncedAt: new Date().toISOString(), + }, + attachments: parsed.pdfAttachments.map((att) => ({ + fileName: att.fileName, + contentType: att.contentType || 'application/pdf', + bytes: att.bytes, + })), + }); + + const alreadyHadArchive = doc.archivePath !== null && doc.archivePath !== ''; + + // 5) DB-Update: archivePath setzen, Artifacts (re-)anlegen, Audit-Log. + // skipDuplicates auf createMany schliesst die Race mit dem + // discoveryDocumentId-kind-fileName-Unique-Constraint. + await prisma.$transaction(async (tx) => { + await tx.discoveryDocument.update({ + where: { id: doc.id }, + data: { archivePath: archive.archivePath }, + }); + // Vorhandene Artifacts loeschen, falls schon welche da sind (z. B. nach + // einem teilweise misslungenen Erst-Sync). Dann frisch anlegen, damit + // die in der DB konsistent zum Filesystem sind. + if (doc._count.artifacts > 0) { + await tx.discoveryArtifact.deleteMany({ where: { discoveryDocumentId: doc.id } }); + } + if (archive.artifacts.length > 0) { + await tx.discoveryArtifact.createMany({ + data: archive.artifacts.map((art) => ({ + discoveryDocumentId: doc.id, + kind: art.kind, + fileName: art.fileName, + contentType: art.contentType, + fileSize: art.fileSize, + sha256: art.sha256, + relativePath: art.relativePath, + })), + skipDuplicates: true, + }); + } + await tx.discoveryAuditLog.create({ + data: { + event: 'IMAP_DOCUMENT_RESYNCED', + sourceId: doc.sourceId, + userId: input.userId, + teamId: input.teamId, + discoveryDocumentId: doc.id, + metadata: { + alreadyHadArchive, + archivePath: archive.archivePath, + artifactCount: archive.artifacts.length, + attachmentCount: parsed.pdfAttachments.length, + }, + }, + }); + }); + + const attachmentsAdded = archive.artifacts.filter((a) => a.kind === 'ATTACHMENT').length; + return { + ok: true, + archivePath: archive.archivePath, + attachmentsAdded, + alreadyHadArchive, + }; +}; diff --git a/packages/lib/server-only/sources/imap/imap-source-adapter.ts b/packages/lib/server-only/sources/imap/imap-source-adapter.ts new file mode 100644 index 0000000..df8c794 --- /dev/null +++ b/packages/lib/server-only/sources/imap/imap-source-adapter.ts @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { ImapFlow } from 'imapflow'; +import { createHash } from 'node:crypto'; + +import { prisma } from '@nexasign/prisma'; + +import { putFileServerSide } from '../../../universal/upload/put-file.server'; +import { createDocumentData } from '../../document-data/create-document-data'; +import { writeArchive } from '../archive'; +import { registerSourceAdapter } from '../registry'; +import type { + SourceAdapter, + SyncRangeContext, + SyncRangeProgress, + SyncRangeResult, + TestConnectionInput, + TestConnectionResult, +} from '../types'; +import { classifyAndExtract } from './classifier'; +import { parseRawMail } from './extract'; +import { validateImapHost } from './host-allowlist'; +import { type ImapAccountConfig, ZImapAccountConfigSchema } from './types'; + +/** + * IMAP-Source-Adapter — Schreib-Pfad in `DiscoveryDocument` für Mail-Belege. + * + * Härtungen aus dem Threat-Model: + * - Host-Allowlist + DNS-Resolution-Check (`validateImapHost`) + * - Connect-Timeout 10 s, Greeting-Timeout 30 s + * - Idempotenz via `messageIdHash` (sha256 vom Message-ID-Header) + * - Kein Body-Speichern: Klassifizierung läuft in-memory, persistiert wird + * nur was in `DiscoveryDocument` als strukturiertes Feld steht + * + * Sync-Modell: User-getriggert mit expliziter Datums-Range. Cancel wird + * pro Mail geprüft; Progress-Reporting alle 25 Mails. + */ + +const CONNECT_TIMEOUT_MS = 10_000; +const GREETING_TIMEOUT_MS = 30_000; + +// Mailbox-Auswahl: Default ist Gmail-typisch. rechnungen.py nutzt das genauso. +// Falls die Mailbox nicht existiert (z.B. Outlook, Fastmail), fallback INBOX. +const PREFERRED_MAILBOXES = ['[Gmail]/Alle Nachrichten', '[Gmail]/All Mail', 'INBOX']; + +const PROGRESS_REPORT_EVERY = 25; +const MAX_MAILS_PER_SYNC = 500; +const MAX_BYTES_PER_SYNC = 20 * 1024 * 1024; + +const parseConfig = (raw: unknown): ImapAccountConfig => { + return ZImapAccountConfigSchema.parse(raw); +}; + +const hashMessageId = (messageId: string): string => + createHash('sha256').update(messageId).digest('hex'); + +const buildClient = (config: ImapAccountConfig): ImapFlow => { + return new ImapFlow({ + host: config.host, + port: config.port, + secure: config.port === 993, + auth: { + user: config.username, + pass: config.password, + }, + tls: { + rejectUnauthorized: config.tlsVerify, + }, + logger: false, + emitLogs: false, + connectionTimeout: CONNECT_TIMEOUT_MS, + greetingTimeout: GREETING_TIMEOUT_MS, + socketTimeout: GREETING_TIMEOUT_MS, + }); +}; + +/** + * Versucht die Mailboxen aus PREFERRED_MAILBOXES nacheinander. Erste, die + * existiert, wird zurückgegeben. Ohne Treffer → null (Adapter wirft). + */ +const pickMailbox = async (client: ImapFlow): Promise => { + const list = await client.list(); + const known = new Set(list.map((entry) => entry.path)); + for (const candidate of PREFERRED_MAILBOXES) { + if (known.has(candidate)) return candidate; + } + return null; +}; + +const testConnection = async (input: TestConnectionInput): Promise => { + let config: ImapAccountConfig; + try { + config = parseConfig(input.config); + } catch { + return { ok: false, error: 'Konfiguration ungültig.' }; + } + + const hostCheck = await validateImapHost(config.host, config.port); + if (!hostCheck.ok) { + return { ok: false, error: hostCheck.reason ?? 'Host nicht erlaubt.' }; + } + + const client = buildClient(config); + try { + await client.connect(); + return { ok: true }; + } catch (err) { + return { + ok: false, + error: err instanceof Error ? err.message : 'Verbindung fehlgeschlagen.', + }; + } finally { + if (client.usable) { + try { + await client.logout(); + } catch { + /* ignore */ + } + } + } +}; + +/** + * User-getriggerter Sync über einen expliziten Zeitraum. Connection-Fehler + * werden geworfen — der Job-Handler entscheidet anhand des Wurfs, ob der + * SyncRun FAILED ist (und Suspend-Counter erhöht). + */ +const syncRange = async (ctx: SyncRangeContext): Promise => { + const config = parseConfig(ctx.decryptedConfig); + + const hostCheck = await validateImapHost(config.host, config.port); + if (!hostCheck.ok) { + throw new Error(hostCheck.reason ?? 'Host-Validierung fehlgeschlagen.'); + } + + const counters: SyncRangeProgress = { + mailsChecked: 0, + documentsAuto: 0, + documentsManual: 0, + documentsIgnored: 0, + documentsFailed: 0, + }; + + const client = buildClient(config); + + try { + await client.connect(); + + const mailbox = await pickMailbox(client); + if (!mailbox) { + throw new Error( + 'Keine geeignete Mailbox gefunden (weder „[Gmail]/Alle Nachrichten" noch „INBOX").', + ); + } + + const lock = await client.getMailboxLock(mailbox); + try { + const search = { + since: ctx.from, + before: ctx.to, + ...(ctx.searchTerm ? { text: ctx.searchTerm } : {}), + }; + + const searchResult = await client.search(search, { uid: true }); + const uids: number[] = Array.isArray(searchResult) ? searchResult : []; + + // Neueste zuerst — ergibt sinnvolle Progress-Reihenfolge im UI. + const orderedUids = uids + .slice() + .sort((a, b) => b - a) + .slice(0, MAX_MAILS_PER_SYNC); + let bytesProcessed = 0; + + for (let i = 0; i < orderedUids.length; i += 1) { + // Cancel alle 10 Mails prüfen (DB-Roundtrip), nicht jedes Mal. + if (i % 10 === 0 && (await ctx.isCancelled())) { + break; + } + + const uid = orderedUids[i]; + try { + const message = await client.fetchOne(String(uid), { source: true }, { uid: true }); + if (!message || !message.source) { + counters.mailsChecked += 1; + continue; + } + + const raw = Buffer.isBuffer(message.source) + ? message.source + : Buffer.from(message.source); + if (bytesProcessed + raw.length > MAX_BYTES_PER_SYNC) { + break; + } + bytesProcessed += raw.length; + + const parsed = await parseRawMail(raw); + counters.mailsChecked += 1; + + if (!parsed.messageId) { + counters.documentsIgnored += 1; + continue; + } + + const messageIdHash = hashMessageId(parsed.messageId); + + // Idempotenz: bereits gesehen → überspringen, zählt nicht als Treffer. + const existing = await prisma.discoveryDocument.findFirst({ + where: { messageIdHash, sourceId: ctx.sourceId }, + select: { id: true }, + }); + if (existing) { + counters.documentsIgnored += 1; + continue; + } + + // Hinweis: der `existing`-Check oben ist KEIN echter Race-Schutz — + // bei parallelen Sync-Runs koennen beide den Datensatz noch nicht sehen + // und beide schreiben. Der echte Schutz ist der Partial-Unique-Index + // (sourceId, messageIdHash) in der DB (Migration 20260430080000_…). + // Das innere try/catch unten faengt Prisma-P2002 ab und behandelt es + // als „bereits vorhanden, ueberspringen", statt als FAILED zu zaehlen. + + const result = classifyAndExtract({ + senderDomain: parsed.fromDomain, + subject: parsed.subject, + bodyText: parsed.bodyText, + hasPdfAttachment: parsed.pdfAttachments.length > 0, + }); + + if (result.verdict === 'IGNORE') { + counters.documentsIgnored += 1; + continue; + } + + // Archive-Write: schreibt mail.eml + body.txt + body.html (optional) + + // metadata.json + attachments idempotent ins Filesystem mit sha256. + const metadata = { + sourceId: ctx.sourceId, + messageIdHash, + messageId: parsed.messageId, + fromName: parsed.fromName, + fromAddress: parsed.fromAddress, + fromDomain: parsed.fromDomain, + subject: parsed.subject, + date: parsed.date.toISOString(), + classification: result.verdict, + detectedAmount: result.detectedAmount, + detectedInvoiceNumber: result.detectedInvoiceNumber, + portalHint: result.portalHint, + providerSource: 'imap', + providerNativeId: String(uid), + attachmentsOriginalNames: parsed.pdfAttachments.map((a) => a.fileName), + }; + + const archive = await writeArchive({ + sourceId: ctx.sourceId, + messageIdHash, + receivedAt: parsed.date, + rawEml: raw, + bodyText: parsed.bodyText, + bodyHtml: parsed.bodyHtml, + metadata, + attachments: parsed.pdfAttachments.map((att) => ({ + fileName: att.fileName, + contentType: att.contentType || 'application/pdf', + bytes: att.bytes, + })), + }); + + if (result.verdict === 'AUTO') { + // Erstes PDF-Attachment ist das primäre DocumentData (für Sign-Flow später). + // Weitere Attachments liegen nur als Artifacts auf disk. + const primary = parsed.pdfAttachments[0]; + const arrayBuffer = primary.bytes.buffer.slice( + primary.bytes.byteOffset, + primary.bytes.byteOffset + primary.bytes.byteLength, + ); + const file = { + name: primary.fileName, + type: 'application/pdf', + arrayBuffer: async () => Promise.resolve(arrayBuffer), + }; + const stored = await putFileServerSide(file); + const dataRecord = await createDocumentData({ + type: stored.type, + data: stored.data, + }); + + await prisma.$transaction(async (tx) => { + const created = await tx.discoveryDocument.create({ + data: { + teamId: ctx.teamId, + uploadedById: ctx.userId, + sourceId: ctx.sourceId, + title: parsed.subject || primary.fileName, + correspondent: parsed.fromName || parsed.fromAddress, + documentDate: parsed.date, + capturedAt: new Date(), + status: 'INBOX', + providerSource: 'imap', + providerNativeId: String(uid), + contentType: 'application/pdf', + fileSize: primary.bytes.byteLength, + tags: [], + detectedAmount: result.detectedAmount, + detectedInvoiceNumber: result.detectedInvoiceNumber, + portalHint: null, + messageIdHash, + bodyText: parsed.bodyText, + bodyHasHtml: parsed.bodyHtml !== null, + archivePath: archive.archivePath, + dataId: dataRecord.id, + }, + select: { id: true }, + }); + await tx.discoveryArtifact.createMany({ + data: archive.artifacts.map((art) => ({ + discoveryDocumentId: created.id, + kind: art.kind, + fileName: art.fileName, + contentType: art.contentType, + fileSize: art.fileSize, + sha256: art.sha256, + relativePath: art.relativePath, + })), + }); + await tx.discoveryAuditLog.create({ + data: { + event: 'IMAP_DOCUMENT_IMPORTED', + sourceId: ctx.sourceId, + userId: ctx.userId, + teamId: ctx.teamId, + discoveryDocumentId: created.id, + metadata: { + messageIdHash, + fromDomain: parsed.fromDomain, + classification: result.verdict, + archivePath: archive.archivePath, + artifactCount: archive.artifacts.length, + }, + }, + }); + }); + counters.documentsAuto += 1; + } else { + // MANUAL — Beleg-Hinweis ohne PDF. DiscoveryDocument mit dataId=null, + // aber Body + Archive werden trotzdem geschrieben. + await prisma.$transaction(async (tx) => { + const created = await tx.discoveryDocument.create({ + data: { + teamId: ctx.teamId, + uploadedById: ctx.userId, + sourceId: ctx.sourceId, + title: parsed.subject || `Beleg-Hinweis von ${parsed.fromDomain}`, + correspondent: parsed.fromName || parsed.fromAddress, + documentDate: parsed.date, + capturedAt: new Date(), + status: 'PENDING_MANUAL', + providerSource: 'imap', + providerNativeId: String(uid), + contentType: null, + fileSize: null, + tags: [], + detectedAmount: result.detectedAmount, + detectedInvoiceNumber: result.detectedInvoiceNumber, + portalHint: result.portalHint, + messageIdHash, + bodyText: parsed.bodyText, + bodyHasHtml: parsed.bodyHtml !== null, + archivePath: archive.archivePath, + dataId: null, + }, + select: { id: true }, + }); + await tx.discoveryArtifact.createMany({ + data: archive.artifacts.map((art) => ({ + discoveryDocumentId: created.id, + kind: art.kind, + fileName: art.fileName, + contentType: art.contentType, + fileSize: art.fileSize, + sha256: art.sha256, + relativePath: art.relativePath, + })), + }); + await tx.discoveryAuditLog.create({ + data: { + event: 'IMAP_DOCUMENT_IMPORTED', + sourceId: ctx.sourceId, + userId: ctx.userId, + teamId: ctx.teamId, + discoveryDocumentId: created.id, + metadata: { + messageIdHash, + fromDomain: parsed.fromDomain, + classification: result.verdict, + portalHint: result.portalHint, + detectedAmount: result.detectedAmount, + detectedInvoiceNumber: result.detectedInvoiceNumber, + archivePath: archive.archivePath, + artifactCount: archive.artifacts.length, + }, + }, + }); + }); + counters.documentsManual += 1; + } + } catch (err) { + // Prisma P2002 = unique constraint violation. Bei (sourceId, messageIdHash) + // bedeutet das: ein paralleler Sync-Run hat den Datensatz zwischen unserem + // findFirst() und create() bereits geschrieben. Kein Fehler — Idempotenz + // greift, wir zaehlen es als ignored und machen weiter. + const code = + err && typeof err === 'object' && 'code' in err + ? (err as { code?: unknown }).code + : undefined; + if (code === 'P2002') { + counters.documentsIgnored += 1; + } else { + counters.documentsFailed += 1; + } + } + + // Progress alle PROGRESS_REPORT_EVERY Mails persistieren. + if ((i + 1) % PROGRESS_REPORT_EVERY === 0) { + await ctx.onProgress({ ...counters }); + } + } + } finally { + lock.release(); + } + } finally { + if (client.usable) { + try { + await client.logout(); + } catch { + /* ignore */ + } + } + } + + // Final-Progress-Report. + await ctx.onProgress({ ...counters }); + + return counters; +}; + +export const imapSourceAdapter: SourceAdapter = { + kind: 'IMAP', + testConnection, + syncRange, +}; + +// Selbst-Registrierung beim Import. Der Job-Handler / Sources-Router muss +// dieses Modul nur einmal importieren, dann ist der Adapter in der Registry. +registerSourceAdapter(imapSourceAdapter); diff --git a/packages/lib/server-only/sources/imap/index.ts b/packages/lib/server-only/sources/imap/index.ts new file mode 100644 index 0000000..941b423 --- /dev/null +++ b/packages/lib/server-only/sources/imap/index.ts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +// Side-effect-Import: registriert imapSourceAdapter in der Registry beim Laden. +import './imap-source-adapter'; + +export { imapSourceAdapter } from './imap-source-adapter'; +export { + encryptImapConfig, + decryptImapConfig, + CURRENT_KEY_VERSION, + type EncryptedImapConfig, +} from './imap-credentials'; +export { + validateImapHost, + getDefaultImapHostAllowlist, + isCustomImapHostsAllowed, + type HostValidationResult, +} from './host-allowlist'; +export type { ImapAccountConfig } from './types'; +export { ZImapAccountConfigSchema } from './types'; +export { resyncSingleDocument } from './imap-resync-single'; +export type { ResyncSingleInput, ResyncSingleResult } from './imap-resync-single'; diff --git a/packages/lib/server-only/sources/imap/keywords.ts b/packages/lib/server-only/sources/imap/keywords.ts new file mode 100644 index 0000000..61c0576 --- /dev/null +++ b/packages/lib/server-only/sources/imap/keywords.ts @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +/** + * Klassifizierungs-Keywords für die IMAP-Discovery-Heuristik. + * + * Direkte Portierung aus dem Prototyp-Script (`Rechnungen erstellen/rechnungen.py`) + * mit den Listen, die sich dort über Monate stabilisiert haben. + */ + +/** Stichwörter, die auf eine Rechnungs-/Beleg-Mail hindeuten (Betreff oder Body). */ +export const RECHNUNG_KEYWORDS: ReadonlyArray = [ + 'rechnung', + 'invoice', + 'beleg', + 'receipt', + 'quittung', + 'zahlungsbestätigung', + 'zahlungsbestaetigung', + 'payment confirmation', + 'abrechnung', + 'gutschrift', + 'kreditnote', + 'credit note', + 'auftragsbestätigung', + 'auftragsbestaetigung', + 'order confirmation', +]; + +/** Absender-Domains, die wir als verlässliche Beleg-Quellen kennen. */ +export const KNOWN_RECHNUNG_DOMAINS: ReadonlyArray = [ + 'hetzner.com', + 'hetzner.de', + 'netcup.de', + 'netcup.eu', + 'all-inkl.com', + 'all-inkl.de', + 'strato.de', + 'strato.com', + 'anthropic.com', + 'openai.com', + 'cloudflare.com', + 'godaddy.com', + 'deutschepost.de', + 'uber.com', + 'flixbus.de', + 'amazon.de', + 'amazon.com', + 'paypal.com', + 'paypal.de', + 'telekom.de', + 'vodafone.de', + 'o2.de', + '1und1.de', + 'ionos.de', + 'premiumsim.de', + 'congstar.de', + 'stripe.com', + 'suno.com', + 'github.com', + 'gitlab.com', + 'google.com', + 'microsoft.com', + 'apple.com', + 'wise.com', + 'n26.com', + 'dkb.de', + 'comdirect.de', + 'ing.de', +]; + +/** Mails, die diese Begriffe enthalten, gelten als Werbung/Newsletter und werden ignoriert. */ +export const IGNORE_KEYWORDS: ReadonlyArray = [ + 'newsletter', + 'unsubscribe', + 'abmelden', + 'sale', + 'rabatt', + '% off', +]; + +/** + * Portal-Hinweise — Mail enthält Beleg-Indikator, aber kein PDF-Anhang. + * Heißt: User muss sich im Kunden-Portal einloggen und dort die PDF ziehen. + */ +export const PORTAL_HINTS: ReadonlyArray = [ + 'im kundenportal', + 'im kundencenter', + 'in der servicewelt', + 'in ihrem konto', + 'im kundenlogin', + 'in ihrem account', + 'einloggen unter', + 'log in to', + 'anmelden unter', + 'rechnung abrufen', + 'rechnung steht zum download bereit', + 'view your invoice', + 'im ccp', + 'control panel', +]; diff --git a/packages/lib/server-only/sources/imap/types.ts b/packages/lib/server-only/sources/imap/types.ts new file mode 100644 index 0000000..8026d59 --- /dev/null +++ b/packages/lib/server-only/sources/imap/types.ts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { z } from 'zod'; + +/** + * IMAP-Konfig — was im Klartext im Sync-Worker liegt. In der DB steht nur das + * verschlüsselte JSON (Source.encryptedConfig). + */ +export const ZImapAccountConfigSchema = z.object({ + host: z.string().min(1).max(255), + port: z.number().int().min(1).max(65535), + username: z.string().min(1).max(255), + password: z.string().min(1).max(1024), + /** Default true. Auf false nur explizit, mit deutlicher UI-Warnung + Audit-Log. */ + tlsVerify: z.boolean(), +}); + +export type ImapAccountConfig = z.infer; diff --git a/packages/lib/server-only/sources/index.ts b/packages/lib/server-only/sources/index.ts new file mode 100644 index 0000000..17e0f72 --- /dev/null +++ b/packages/lib/server-only/sources/index.ts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors + +export { getSourceAdapter, listRegisteredKinds, registerSourceAdapter } from './registry'; +export type { + SourceAdapter, + SyncRangeContext, + SyncRangeProgress, + SyncRangeResult, + TestConnectionInput, + TestConnectionResult, +} from './types'; diff --git a/packages/lib/server-only/sources/registry.ts b/packages/lib/server-only/sources/registry.ts new file mode 100644 index 0000000..9488e49 --- /dev/null +++ b/packages/lib/server-only/sources/registry.ts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import type { SourceKind } from '@prisma/client'; + +import type { SourceAdapter } from './types'; + +const adapters = new Map(); + +/** + * Adapter-Registrierung — wird vom IMAP-Modul (Welle 2) zur Modul-Initialisierung + * aufgerufen. Sources-Router nutzt `getSourceAdapter`, um zur richtigen + * Implementierung zu dispatchen, ohne hart darauf zu importieren. + */ +export const registerSourceAdapter = (adapter: SourceAdapter): void => { + adapters.set(adapter.kind, adapter); +}; + +export const getSourceAdapter = (kind: SourceKind): SourceAdapter | undefined => { + return adapters.get(kind); +}; + +export const listRegisteredKinds = (): SourceKind[] => { + return Array.from(adapters.keys()); +}; diff --git a/packages/lib/server-only/sources/types.ts b/packages/lib/server-only/sources/types.ts new file mode 100644 index 0000000..5971c97 --- /dev/null +++ b/packages/lib/server-only/sources/types.ts @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import type { SourceKind } from '@prisma/client'; + +/** + * Ausführungs-Kontext für einen User-getriggerten Sync-Lauf über einen + * expliziten Zeitraum. Die Konfig (host, port, credentials, …) ist bereits + * entschlüsselt — der Adapter muss nicht mit `encryptedConfig` umgehen. + */ +export type SyncRangeContext = { + sourceId: string; + userId: number; + teamId: number; + /** Beginn des User-gewählten Suchzeitraums (inklusiv). */ + from: Date; + /** Ende des User-gewählten Suchzeitraums (exklusiv). */ + to: Date; + /** Optionaler Suchbegriff für Betreff/Header/Body, z. B. "Rechnung". */ + searchTerm?: string | null; + /** Adapter-spezifische Konfig nach Decrypt. Adapter validiert selbst. */ + decryptedConfig: unknown; + /** Cancel-Polling — Adapter prüft das pro Mail. */ + isCancelled: () => Promise; + /** Progress-Reporting — Adapter ruft das in Intervallen auf. */ + onProgress: (progress: SyncRangeProgress) => Promise; +}; + +export type SyncRangeProgress = { + mailsChecked: number; + documentsAuto: number; + documentsManual: number; + documentsIgnored: number; + documentsFailed: number; +}; + +export type SyncRangeResult = SyncRangeProgress; + +export type TestConnectionInput = { + config: unknown; +}; + +export type TestConnectionResult = { + ok: boolean; + error?: string; +}; + +/** + * SourceAdapter-Interface — pro Source-Typ (IMAP, später Cloud) eine + * Implementierung. Der Adapter ist der Schreib-Pfad in `DiscoveryDocument`; + * der Lese-Pfad lebt im DiscoveryReader (db-reader). + * + * Es gibt keinen impliziten „seit-letztem-Sync"-Cursor mehr — jeder Lauf + * bekommt einen expliziten Zeitraum vom User. + */ +export interface SourceAdapter { + readonly kind: SourceKind; + + /** Verbindungstest gegen die übergebene Konfig — kein Schreib-Effekt. */ + testConnection(input: TestConnectionInput): Promise; + + /** User-getriggerter Sync über einen expliziten Zeitraum. */ + syncRange(ctx: SyncRangeContext): Promise; +} diff --git a/packages/lib/server-only/team/create-team-email-verification.ts b/packages/lib/server-only/team/create-team-email-verification.ts index 4fd2607..acd4a5d 100644 --- a/packages/lib/server-only/team/create-team-email-verification.ts +++ b/packages/lib/server-only/team/create-team-email-verification.ts @@ -142,7 +142,7 @@ export const sendTeamEmailVerificationEmail = async (email: string, token: strin to: email, from: senderEmail, subject: i18n._( - msg`A request to use your email has been initiated by ${team.name} on NexaSign`, + msg`A request to use your email has been initiated by ${team.name} on NexaFile`, ), html, text, diff --git a/packages/lib/server-only/team/delete-team.ts b/packages/lib/server-only/team/delete-team.ts index 1a6d594..3316c22 100644 --- a/packages/lib/server-only/team/delete-team.ts +++ b/packages/lib/server-only/team/delete-team.ts @@ -144,7 +144,7 @@ export const sendTeamDeleteEmail = async ({ await mailer.sendMail({ to: email, from: senderEmail, - subject: i18n._(msg`Team "${team.name}" has been deleted on NexaSign`), + subject: i18n._(msg`Team "${team.name}" has been deleted on NexaFile`), html, text, }); diff --git a/packages/lib/server-only/telemetry/telemetry-client.ts b/packages/lib/server-only/telemetry/telemetry-client.ts index 9f14575..7f5b4a0 100644 --- a/packages/lib/server-only/telemetry/telemetry-client.ts +++ b/packages/lib/server-only/telemetry/telemetry-client.ts @@ -108,7 +108,7 @@ export class TelemetryClient { this.nodeId = await this.getOrCreateNodeId(); console.log( - '[Telemetry] Telemetry is enabled. NexaSign collects anonymous usage data to help improve the product.', + '[Telemetry] Telemetry is enabled. NexaFile collects anonymous usage data to help improve the product.', ); console.log( '[Telemetry] We collect: app version, installation ID, and node ID. No personal data, document contents, or user information is collected.', diff --git a/packages/lib/translations/de/web.po b/packages/lib/translations/de/web.po index e7de74e..a6de60f 100644 --- a/packages/lib/translations/de/web.po +++ b/packages/lib/translations/de/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, one {Du bist dabei, die ausgewählte Vorlage zu löschen.} o msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "{0}-Feld" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} hat Sie eingeladen, das Dokument \"{1}\" {recipientActionVerb}." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0} im Namen von \"{1}\" hat Sie eingeladen, das Dokument \"{2}\" {recip msgid "{0} Teams" msgstr "{0} Teams" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} auf {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {1 Zeichen verbleibend} other {{charactersRemaining} Zeichen verbleibend}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {Dieser Code wird in # Minute ablaufen.} other {Dieser Code wird in # Minuten ablaufen.}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference} hat {documentName} unterschrieben" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {# Zeichen verbleibend} other {# Zeichen verbleibend}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount} ausgewählt" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} hat angefragt, ein Konto in Ihrem Namen zu erstellen." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} hat angefragt, Ihr bestehendes NexaSign-Konto mit ihrer Organisation zu verknüpfen." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail} im Namen von \"{0}\" hat Sie eingeladen, dieses Dokument anzusehen" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} hat angefragt, Ihre E-Mail-Adresse für ihr Team bei NexaSign zu verwenden." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>Jede Person – Jede Person kann auf das Dokument zugreifen und e msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Voller Zugang zum Konto: Sehen Sie alle Ihre Profilinformationen, Einstellungen und Aktivitäten." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Authentifizierungsmethode erben - Verwenden Sie die in den \"Allgemeinen Einstellungen\" konfigurierte globale Aktionssignatur-Authentifizierungsmethode" @@ -790,6 +821,10 @@ msgstr "1 Freie Organisationen übrig" msgid "1 month" msgstr "1 Monat" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 Monate" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "Ein Mittel, um Dokumente für Ihre Unterlagen zu drucken oder herunterzuladen" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "Ein Mitglied ist Ihrer Organisation bei NexaSign beigetreten" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "Ein Mitglied hat Ihre Organisation {organisationName} verlassen" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "Ein Mitglied hat Ihre Organisation auf NexaSign verlassen" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "Es wurde eine Anfrage gestellt, ein Konto für Sie zu erstellen." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "Es wurde eine Anfrage gestellt, Ihr NexaSign-Konto zu verknüpfen." +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "Eine Anfrage zur Verwendung Ihrer E-Mail wurde von {0} auf NexaSign initiiert" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "Ein Geheimnis, das an deine URL gesendet wird, damit du überprüfen kannst, dass die Anfrage von NexaSign gesendet wurde." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "Eine gültige E-Mail-Adresse ist erforderlich" msgid "A verification email will be sent to the provided email." msgstr "Eine Bestätigungs-E-Mail wird an die angegebene E-Mail-Adresse gesendet." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "Akzeptieren & Konto verknüpfen" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Einladung annehmen, um einer Organisation auf NexaSign beizutreten" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Akzeptiere die Team-E-Mail-Anfrage für {teamName} bei NexaSign" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "KI‑Funktionen" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "KI-Funktionen sind für Ihr Team deaktiviert. Bitte bitten Sie den Teambesitzer oder den Organisationsbesitzer, sie zu aktivieren." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "Alle Vorlagen" msgid "All Time" msgstr "Alle Zeiten" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Erlaube allen Organisationsmitgliedern den Zugriff auf dieses Team" @@ -1576,6 +1666,14 @@ msgstr "Fast fertig" msgid "Already have an account? <0>Sign in instead" msgstr "Hast du bereits ein Konto? <0>Stattdessen anmelden" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Betrag" @@ -1889,6 +1987,19 @@ msgstr "Seitenlayout wird analysiert" msgid "Analyzing pages" msgstr "Seiten werden analysiert" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Alle Dokumente, zu denen Sie eingeladen wurden, erscheinen hier" @@ -1913,6 +2024,10 @@ msgstr "API-Token" msgid "App Version" msgstr "App-Version" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "Genehmigung" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "Sind Sie sicher, dass Sie das Dokument abschließen möchten? Diese Aktion kann nicht rückgängig gemacht werden. Bitte stellen Sie sicher, dass Sie alle relevanten Felder vorab ausgefüllt haben, bevor Sie fortfahren." @@ -2116,6 +2244,10 @@ msgstr "Audit-Log-Details" msgid "Audit Logs" msgstr "Protokolle" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "Backup-Codes" msgid "Banner Updated" msgstr "Banner aktualisiert" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Bitte bestätige vor dem Start deine E-Mail-Adresse, indem du auf den Button unten klickst:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "Abrechnung" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Schwarz" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "Wenn 2FA aktiviert wird, müssen Sie bei jedem Anmelden mit E-Mail-Passwort einen Code aus Ihrer Authentifikator-App eingeben." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "Indem Sie den elektronischen Unterzeichnungsdienst von NexaSign verwenden, bestätigen Sie, dass Sie diese Offenlegung gelesen und verstanden haben. Sie stimmen allen Bedingungen und Konditionen zu, die mit der Verwendung elektronischer Unterschriften und elektronischer Transaktionen verbunden sind, wie hierin dargelegt." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "Dokument wird erstellt" msgid "Creating Template" msgstr "Vorlage wird erstellt" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "CSV-Struktur" @@ -3338,6 +3535,10 @@ msgstr "Benutzerdefinierte Organisationsgruppen" msgid "Dark Mode" msgstr "Dunkelmodus" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "Datumsformat" msgid "Date Settings" msgstr "Datumseinstellungen" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David ist der Mitarbeiter, Lucas ist der Manager" @@ -3625,11 +3834,20 @@ msgstr "Gelöscht" msgid "Deleting account..." msgstr "Konto wird gelöscht..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Ziel" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "Gerät" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "Du hast keine Passwortänderung angefordert? Wir helfen dir, dein Konto zu sichern, kontaktiere uns einfach <0>hier." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "Dokumentation" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "Dokumente, bei denen alle Empfänger unterschrieben haben, das Dokument msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "Zeichnen" msgid "Draw signature" msgstr "Unterschrift zeichnen" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "PDF hier ablegen oder klicken, um auszuwählen" @@ -4433,10 +4690,22 @@ msgstr "Vorlage duplizieren" msgid "Duplicate values are not allowed" msgstr "Doppelte Werte sind nicht erlaubt" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "Niederländisch" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "z. B. Legal" msgid "eg. Mac" msgstr "z. B. Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Elektronische Zustellung von Dokumenten" @@ -4800,6 +5077,10 @@ msgstr "Beigefügte Dokument" msgid "Enclosed Documents" msgstr "Beigefügte Dokumente" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "Englisch" @@ -4906,6 +5187,10 @@ msgstr "Geben Sie hier Ihren Text ein" msgid "Enterprise" msgstr "Unternehmen" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Umschlag verteilt" @@ -4952,6 +5237,14 @@ msgstr "Umschlagtitel" msgid "Envelope updated" msgstr "Umschlag aktualisiert" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "Fehler beim Laden der Seite" msgid "Error uploading file" msgstr "Fehler beim Hochladen der Datei" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "Läuft ab in {0}" msgid "Expires on {0}" msgstr "Läuft ab am {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "Externe ID" msgid "Extracting contact details" msgstr "Kontaktdaten werden extrahiert" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "Funktionsflaggen" msgid "Features" msgstr "Funktionen" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Zeichenbeschränkung des Feldes" @@ -5337,6 +5650,10 @@ msgstr "Füllen Sie die Details aus, um einen neuen Abonnementsanspruch zu erste msgid "Filter by status" msgstr "Nach Status filtern" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "Französisch" msgid "Full Name" msgstr "Vollständiger Name" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "Links generieren" msgid "German" msgstr "Deutsch" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Globale Empfängerauthentifizierung" @@ -5556,6 +5890,22 @@ msgstr "Zum Team gehen" msgid "Go to your <0>public profile settings to add documents." msgstr "Gehen Sie zu Ihren <0>öffentlichen Profileinstellungen, um Dokumente hinzuzufügen." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Grün" @@ -5686,6 +6036,14 @@ msgstr "Ausblenden" msgid "Hide license key" msgstr "Lizenzschlüssel ausblenden" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "Horizontal" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "Wie lange Empfänger Zeit haben, dieses Dokument nach dem Senden zu vervollständigen. Verwendet die Team-Standardeinstellung, wenn \"Vererben\" ausgewählt ist." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "Ich bin einverstanden, mein Konto mit dieser Organisation zu verknüpfen." @@ -5790,10 +6152,41 @@ msgstr "Wenn Sie den Bestätigungslink nicht in Ihrem Posteingang finden, könne msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "Wenn Ihre Authenticator-App keine QR-Codes unterstützt, können Sie stattdessen den folgenden Code verwenden:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Wichtig: Was dies bedeutet" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "Enthält:" msgid "Information" msgstr "Information" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Authentifizierungsmethode erben" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "Ungültiger Lizenzschlüssel" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "Ungültiger Lizenztyp – Ihre NexaSign-Instanz verwendet Funktionen, die nicht Teil Ihrer Lizenz sind." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "Japanisch" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Tritt {organisationName} auf NexaSign bei" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "Beigetreten" msgid "Joined {0}" msgstr "Beigetreten {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "Zentrale Kennungen und Beziehungen für dieses Team." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "Koreanisch" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "Koreanisch" msgid "Label" msgstr "Beschriftung" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "Buchstabenspacing" msgid "Letter Spacing" msgstr "Buchstabenspacing" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "Lichtmodus" msgid "Like to have your own public profile with agreements?" msgstr "Möchten Sie Ihr eigenes öffentliches Profil mit Vereinbarungen haben?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Zeilenhöhe" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "Vorlage verknüpfen" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Verknüpfen Sie Ihr NexaSign-Konto" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "Formularfelder werden gesucht" msgid "Looking for signature fields" msgstr "Signaturfelder werden gesucht" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "Manager" msgid "Managers and above" msgstr "Manager und höher" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Felder werden Empfängern zugeordnet" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "Min" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "Fehlende Lizenz – Ihre NexaSign-Instanz verwendet Funktionen, für die eine Lizenz erforderlich ist." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "Mein Ordner" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "Muss unterzeichnen" msgid "Needs to view" msgstr "Muss sehen" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Niemals" @@ -6791,13 +7267,21 @@ msgstr "Neue Option {0}" msgid "New Password" msgstr "Neues Passwort" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "NexaSign-Lizenz" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign wird <0>alle Ihre Dokumente löschen, zusammen mit allen abgeschlossenen Dokumenten, Unterschriften und allen anderen Ressourcen, die zu Ihrem Konto gehören." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "Kein Wert gefunden." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "Keine Sorge, das passiert! Geben Sie Ihre E-Mail ein, und wir senden Ihnen einen speziellen Link zum Zurücksetzen Ihres Passworts." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "Anzahl der erlaubten Teams. 0 = Unbegrenzt" msgid "Number Settings" msgstr "Zahleneinstellungen" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "Aus" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "Ein" @@ -7545,6 +8049,10 @@ msgstr "Ausstehende Organisations­einladungen" msgid "Pending since" msgstr "Ausstehend seit" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "Persönliches Konto" msgid "Personal Inbox" msgstr "Persönlicher Posteingang" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "Bitte laden Sie ein Logo hoch" msgid "Polish" msgstr "Polnisch" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "Portugiesisch (Brasilien)" @@ -7824,6 +8344,14 @@ msgstr "Pos. X:" msgid "Pos Y:" msgstr "Pos. Y:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "Öffentliche Vorlage" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Öffentliche Vorlagen sind mit Ihrem öffentlichen Profil verbunden. Änderungen an öffentlichen Vorlagen erscheinen auch in Ihrem öffentlichen Profil." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Schnellaktionen" @@ -7980,6 +8558,11 @@ msgstr "Erneut registrieren" msgid "Re-register Email Domain" msgstr "E-Mail-Domain erneut registrieren" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "Nur lesen" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Lesen Sie unsere Dokumentation, um mit NexaSign zu beginnen." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "Ihr Dokument wird gelesen" msgid "Ready" msgstr "Bereit" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "Aktuelle Aktivitäten" msgid "Recent documents" msgstr "Neueste Dokumente" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "Eingeschränkter Zugriff" msgid "Retention of Documents" msgstr "Aufbewahrung von Dokumenten" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Erneut versucht" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "Zurück zur Startseite" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Hier zur NexaSign-Anmeldeseite zurückkehren" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "Registrieren mit Microsoft" msgid "Sign Up with OIDC" msgstr "Registrieren mit OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "Überspringen" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "Durch Leerzeichen getrennte Liste von Domains. Leer lassen, um alle Doma msgid "Spanish" msgstr "Spanisch" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Statistiken" @@ -9592,6 +10224,7 @@ msgstr "Statistiken" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "Passkey erfolgreich erstellt" msgid "Successfully created: {successCount}" msgstr "Erfolgreich erstellt: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Zusammenfassung:" @@ -9790,6 +10431,18 @@ msgstr "Synchronisierung fehlgeschlagen, Änderungen nicht gespeichert" msgid "Sync license from server" msgstr "Lizenz mit Server synchronisieren" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "Zielorganisation" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Team" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "Team \"{0}\" wurde auf NexaSign gelöscht" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "Team Admin" msgid "Team Assignments" msgstr "Teamzuweisungen" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "Team-E-Mail entfernt" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "Team-E-Mail für {teamName} auf NexaSign entfernt" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "Vorlage hochgeladen" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "Vorlagen teilweise gelöscht" msgid "Test" msgstr "Test" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Test-Webhook" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "Danke, dass Sie den Signaturvorgang abgeschlossen haben." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Vielen Dank, dass Sie NexaSign zur elektronischen Unterzeichnung Ihrer Dokumente verwenden. Der Zweck dieser Offenlegung besteht darin, Sie über den Prozess, die Rechtmäßigkeit und Ihre Rechte in Bezug auf die Verwendung elektronischer Unterschriften auf unserer Plattform zu informieren. Indem Sie sich entscheiden, eine elektronische Unterschrift zu verwenden, stimmen Sie den nachfolgend dargelegten Bedingungen zu." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "Die Signaturtypen, die Empfänger beim Unterschreiben des Dokuments verw #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "Die URL für NexaSign, um Webhook-Ereignisse zu senden." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "Dieses Dokument wurde von allen Empfängern unterschrieben" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "Dieses Dokument ist in Ihrem NexaSign-Konto verfügbar. Dort können Sie weitere Details, Empfänger und Protokolle einsehen." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "Dieses Dokument wurde mit einem direkten Link erstellt." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "Titel" msgid "Title cannot be empty" msgstr "Titel darf nicht leer sein" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "Um diese Einladung anzunehmen, müssen Sie ein Konto erstellen." @@ -11347,6 +12013,10 @@ msgstr "Lösen" msgid "Unsealed Documents" msgstr "Unversiegelte Dokumente" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "Validierung fehlgeschlagen" msgid "Value" msgstr "Wert" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Verifizierungscode erforderlich" @@ -11782,6 +12483,10 @@ msgstr "Vertikal" msgid "Vertical Align" msgstr "Vertikale Ausrichtung" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "Betrachten" msgid "Visibility" msgstr "Sichtbarkeit" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "Warten" @@ -11986,8 +12712,8 @@ msgstr "Warten auf deine Reihe" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "Möchtest du schicke Signatur-Links wie diesen versenden? <0>Sieh dir NexaSign an." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "Möchten Sie Ihr eigenes öffentliches Profil haben?" msgid "Warning: Assistant as last signer" msgstr "Warnung: Assistent als letzter Unterzeichner" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "Willkommen bei {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "Willkommen bei NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "Ob das SSO-Portal für Ihre Organisation aktiviert werden soll" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "Während Sie darauf warten, können Sie Ihr eigenes NexaSign-Konto erstellen und sofort mit der Dokumentenunterzeichnung beginnen." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "Wen möchten Sie erinnern?" msgid "Width:" msgstr "Breite:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Zustimmung widerrufen" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "Sie können Felder nur in Entwürfen von Umschlägen erkennen." #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "Sie können den Zugriff jederzeit in Ihren Teameinstellungen auf NexaSign <0>hier widerrufen." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "Sie wurden von <0>{0} eingeladen, deren Organisation beizutreten." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "Du wurdest eingeladen, {0} auf NexaSign beizutreten" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "Ihre E-Mail" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "Ihre E-Mail wurde bereits bestätigt. Sie können jetzt alle Funktionen von NexaSign nutzen." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "Ihre E-Mail wurde erfolgreich bestätigt! Sie können jetzt alle Funktionen von NexaSign nutzen." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Ihr Plan unterstützt keine Mitglieder-Einladungen. Bitte aktualisieren Sie Ihren Plan oder kontaktieren Sie den Vertrieb unter <0>{SUPPORT_EMAIL}, wenn Sie Ihre Optionen besprechen möchten." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Ihr Plan ist nicht mehr gültig. Bitte abonnieren Sie einen neuen Plan, um NexaSign weiter zu nutzen." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "Ihr Verifizierungscode:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/en/web.po b/packages/lib/translations/en/web.po index b05cbae..c77d284 100644 --- a/packages/lib/translations/en/web.po +++ b/packages/lib/translations/en/web.po @@ -247,6 +247,11 @@ msgstr "{0, plural, one {You are about to delete the selected template.} other { msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "{0} Anhang/Anhänge wieder verfügbar." + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -263,6 +268,14 @@ msgstr "{0} field" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} has invited you to {recipientActionVerb} the document \"{1}\"." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -288,6 +301,12 @@ msgstr "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the do msgid "{0} Teams" msgstr "{0} Teams" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "{0} von {1} angezeigt" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -323,6 +342,10 @@ msgstr "{browserInfo} on {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" @@ -429,6 +452,10 @@ msgstr "{recipientReference} has signed {documentName}" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "{selectedCount} ausgewählt" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount} selected" @@ -625,8 +652,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} has requested to create an account on your behalf." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} has requested to link your current NexaSign account to their organisation." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "<0>{organisationName} has requested to link your current NexaFile account to their organisation." #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -665,8 +692,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to view this document" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} has requested to use your email address for their team on NexaSign." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "<0>{teamName} has requested to use your email address for their team on NexaFile." #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -701,6 +728,10 @@ msgstr "<0>Everyone - Everyone can access and view the document" msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Full account access: View all your profile information, settings, and activity" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" @@ -785,6 +816,10 @@ msgstr "1 Free organisations left" msgid "1 month" msgstr "1 month" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 months" @@ -924,8 +959,8 @@ msgid "A means to print or download documents for your records" msgstr "A means to print or download documents for your records" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "A member has joined your organisation on NexaSign" +msgid "A member has joined your organisation on NexaFile" +msgstr "A member has joined your organisation on NexaFile" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -936,8 +971,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "A member has left your organisation {organisationName}" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "A member has left your organisation on NexaSign" +msgid "A member has left your organisation on NexaFile" +msgstr "A member has left your organisation on NexaFile" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -976,18 +1011,18 @@ msgid "A request has been made to create an account for you" msgstr "A request has been made to create an account for you" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "A request has been made to link your NexaSign account" +msgid "A request has been made to link your NexaFile account" +msgstr "A request has been made to link your NexaFile account" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "A request to use your email has been initiated by {0} on NexaSign" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "A request to use your email has been initiated by {0} on NexaFile" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1023,6 +1058,18 @@ msgstr "A valid email is required" msgid "A verification email will be sent to the provided email." msgstr "A verification email will be sent to the provided email." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "Abbrechen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "Abbruch fehlgeschlagen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "Abbruch wird ausgeführt" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1034,12 +1081,12 @@ msgid "Accept & Link Account" msgstr "Accept & Link Account" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Accept invitation to join an organisation on NexaSign" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "Accept invitation to join an organisation on NexaFile" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Accept team email request for {teamName} on NexaSign" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "Accept team email request for {teamName} on NexaFile" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1456,6 +1503,37 @@ msgstr "AI Features" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "Aktion" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "Aktion ausgeführt" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "Aktion fehlgeschlagen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "Aktiv" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "Akzeptieren" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "Akzeptiert" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "Akzeptiert · GoBD-gesperrt" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1528,6 +1606,18 @@ msgstr "All templates" msgid "All Time" msgstr "All Time" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "Alle" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "Alle Belege" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "Alle Quellen" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Allow all organisation members to access this team" @@ -1571,6 +1661,14 @@ msgstr "Almost done" msgid "Already have an account? <0>Sign in instead" msgstr "Already have an account? <0>Sign in instead" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "Als Beleg akzeptieren" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "Als manuell zu ziehen markieren" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Amount" @@ -1884,6 +1982,19 @@ msgstr "Analyzing page layout" msgid "Analyzing pages" msgstr "Analyzing pages" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "Anbieter" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "Anbieter auswählen" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "Anhänge + Mail als ZIP" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Any documents that you have been invited to will appear here" @@ -1908,6 +2019,10 @@ msgstr "API Tokens" msgid "App Version" msgstr "App Version" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "App-Passwort" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1957,6 +2072,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "Approving" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "Archiv" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "Archivieren" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." @@ -2111,6 +2239,10 @@ msgstr "Audit Log Details" msgid "Audit Logs" msgstr "Audit Logs" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "Auswahl aufheben" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2179,14 +2311,67 @@ msgstr "Backup codes" msgid "Banner Updated" msgstr "Banner Updated" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "Bausteine" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "Beendet {0}" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Before you get started, please confirm your email address by clicking the button below:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "Beispiel-Nutzer" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "Beleg nicht gefunden" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "Beleg-Detail" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "Belege ziehen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "Betrag" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "Betreff" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "Bezeichnung" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2197,6 +2382,14 @@ msgstr "Beispiel-Nutzer" msgid "Billing" msgstr "Billing" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "Bis" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "Bis (exklusiv)" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Black" @@ -2308,8 +2501,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "By enabling 2FA, you will be required to enter a code from your authenticator app every time you sign in using email password." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3276,6 +3469,10 @@ msgstr "Creating Document" msgid "Creating Template" msgstr "Creating Template" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "CSV exportieren" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "CSV Structure" @@ -3333,6 +3530,10 @@ msgstr "Custom Organisation Groups" msgid "Dark Mode" msgstr "Dark Mode" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "Das Von-Datum muss vor dem Bis-Datum liegen." + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3368,6 +3569,14 @@ msgstr "Date Format" msgid "Date Settings" msgstr "Date Settings" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "Dateien im Archiv" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "Datum" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David is the Employee, Lucas is the Manager" @@ -3620,11 +3829,20 @@ msgstr "Deleted" msgid "Deleting account..." msgstr "Deleting account..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "Der Fortschritt wird unten angezeigt." + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Destination" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3691,6 +3909,22 @@ msgstr "Device" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "Didn't request a password change? We are here to help you secure your account, just <0>contact us." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "Die Verantwortungs-Teilung" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "Diese Quelle existiert nicht oder wurde gelöscht." + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "Diese Quelle ist gesperrt." + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4192,8 +4426,6 @@ msgid "Documentation" msgstr "Documentation" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4255,6 +4487,27 @@ msgstr "Documents where all recipients have signed but the document has not been msgid "Dokumente" msgstr "Dokumente" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "Dokumente archivieren" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "Dokumente erstellen" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "Dokumente finden" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "Dokumente signieren" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4366,6 +4619,10 @@ msgstr "Draw" msgid "Draw signature" msgstr "Draw signature" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "Drop PDF here or click to select" @@ -4428,10 +4685,22 @@ msgstr "Duplicate Template" msgid "Duplicate values are not allowed" msgstr "Duplicate values are not allowed" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "Durchsuchen" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "Durchsuchung konnte nicht gestartet werden" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "Dutch" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "E-Mail-Adresse" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4476,6 +4745,14 @@ msgstr "eg. Legal" msgid "eg. Mac" msgstr "eg. Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "Eigenen Host eingeben…" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "Eingang" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Electronic Delivery of Documents" @@ -4795,6 +5072,10 @@ msgstr "Enclosed Document" msgid "Enclosed Documents" msgstr "Enclosed Documents" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "Endgültig entfernen" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "English" @@ -4901,6 +5182,10 @@ msgstr "Enter your text here" msgid "Enterprise" msgstr "Enterprise" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "Entfernen fehlgeschlagen" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Envelope distributed" @@ -4947,6 +5232,14 @@ msgstr "Envelope Title" msgid "Envelope updated" msgstr "Envelope updated" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "Erkannter Betrag" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "Erneut aus IMAP laden" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5043,6 +5336,14 @@ msgstr "Error loading page" msgid "Error uploading file" msgstr "Error uploading file" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "Erster Sync läuft im Hintergrund." + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5111,6 +5412,10 @@ msgstr "Expires in {0}" msgid "Expires on {0}" msgstr "Expires on {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "Export-CLI — " + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5121,6 +5426,10 @@ msgstr "External ID" msgid "Extracting contact details" msgstr "Extracting contact details" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "Fachbegriffe & FAQ" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5252,6 +5561,10 @@ msgstr "Feature Flags" msgid "Features" msgstr "Features" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "Fehler" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Field character limit" @@ -5332,6 +5645,10 @@ msgstr "Fill in the details to create a new subscription claim." msgid "Filter by status" msgstr "Filter by status" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "Finanzamt-Zugriff: Z1, Z2, Z3" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5444,6 +5761,10 @@ msgstr "French" msgid "Full Name" msgstr "Full Name" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5468,6 +5789,19 @@ msgstr "Generate Links" msgid "German" msgstr "German" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "Geschäftspostfach" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "Gesperrt" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "Gestartet {0}" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Global recipient action authentication" @@ -5551,6 +5885,22 @@ msgstr "Go to team" msgid "Go to your <0>public profile settings to add documents." msgstr "Go to your <0>public profile settings to add documents." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "GoBD-Archivierung" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "GoBD-konforme Archivierung mit NexaFile" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Green" @@ -5681,6 +6031,14 @@ msgstr "Hide" msgid "Hide license key" msgstr "Hide license key" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5705,6 +6063,10 @@ msgstr "Horizontal" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "I agree to link my account with this organization" @@ -5785,10 +6147,41 @@ msgstr "If you don't find the confirmation link in your inbox, you can request a msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "If your authenticator app does not support QR codes, you can use the following code instead:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "Ignorieren" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "Ignoriert" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "IMAP-Konto · Belege fließen in Team „{0}\"" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "IMAP-Konto · Team: {0}" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "IMAP-Konto verbinden" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Important: What This Means" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "In Gmail öffnen" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5842,6 +6235,10 @@ msgstr "Includes:" msgid "Information" msgstr "Information" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "Inhalt des Export-Pakets" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Inherit authentication method" @@ -5932,8 +6329,8 @@ msgid "Invalid License Key" msgstr "Invalid License Key" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "Invalid License Type - Your NexaSign instance is using features that are not part of your license." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "Invalid License Type - Your NexaFile instance is using features that are not part of your license." #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6063,8 +6460,8 @@ msgid "Japanese" msgstr "Japanese" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Join {organisationName} on NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "Join {organisationName} on NexaFile" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6077,14 +6474,38 @@ msgstr "Joined" msgid "Joined {0}" msgstr "Joined {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "Kein Anhang" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "Keine Belege im aktuellen Bereich" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "Key identifiers and relationships for this team." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "Korean" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "Korrespondent" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6097,6 +6518,10 @@ msgstr "Korean" msgid "Label" msgstr "Label" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "Laden" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6208,6 +6633,23 @@ msgstr "Letter spacing" msgid "Letter Spacing" msgstr "Letter Spacing" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "Letzter Monat" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "Letzter Sync: {0}" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "Letztes Jahr" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "Letztes Quartal" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6237,6 +6679,11 @@ msgstr "Light Mode" msgid "Like to have your own public profile with agreements?" msgstr "Like to have your own public profile with agreements?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Line height" @@ -6259,8 +6706,8 @@ msgid "Link template" msgstr "Link template" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Link your NexaSign account" +msgid "Link your NexaFile account" +msgstr "Link your NexaFile account" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6332,6 +6779,14 @@ msgstr "Looking for form fields" msgid "Looking for signature fields" msgstr "Looking for signature fields" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "Mail erneut aus IMAP geladen" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "Mail-Inhalt" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6501,6 +6956,15 @@ msgstr "Manager" msgid "Managers and above" msgstr "Managers and above" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "Manuell" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "Manuell zu ziehen" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Mapping fields to recipients" @@ -6604,8 +7068,8 @@ msgid "Min" msgstr "Min" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "Missing License - Your NexaSign instance is using features that require a license." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "Missing License - Your NexaFile instance is using features that require a license." #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6697,6 +7161,10 @@ msgstr "My Folder" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6757,6 +7225,14 @@ msgstr "Needs to sign" msgid "Needs to view" msgstr "Needs to view" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "Neu" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "Neuen Sync-Lauf starten" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Never" @@ -6786,13 +7262,21 @@ msgstr "New option {0}" msgid "New Password" msgstr "New Password" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "NexaSign License" +msgid "NexaFile License" +msgstr "NexaFile License" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7000,6 +7484,18 @@ msgstr "No value found." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "No worries, it happens! Enter your email and we'll email you a special link to reset your password." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "Noch kein Sync gestartet" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "Noch keine Quelle verbunden" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7070,10 +7566,18 @@ msgstr "Number of teams allowed. 0 = Unlimited" msgid "Number Settings" msgstr "Number Settings" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "Nutzung" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "Off" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "On" @@ -7540,6 +8044,10 @@ msgstr "Pending Organisation Invites" msgid "Pending since" msgstr "Pending since" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7568,6 +8076,10 @@ msgstr "Personal Account" msgid "Personal Inbox" msgstr "Personal Inbox" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "Pfad auf dem Server" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7805,6 +8317,14 @@ msgstr "Please upload a logo" msgid "Polish" msgstr "Polish" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "Port" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "Portal-Hinweis (Mail enthält)" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "Portuguese (Brazil)" @@ -7819,6 +8339,14 @@ msgstr "Pos X:" msgid "Pos Y:" msgstr "Pos Y:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "Postfach durchsuchen" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "Postfach-Durchsuchung gestartet" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7944,6 +8472,56 @@ msgstr "Public Template" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "Quelle" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "Quelle entfernen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "Quelle entfernt" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "Quelle hinzugefügt" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "Quelle nicht gefunden" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "Quelle reaktiviert" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "Quelle verbinden" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "Quelle wirklich entfernen?" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "Quellen" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "Quellen verwalten" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Quick Actions" @@ -7975,6 +8553,11 @@ msgstr "Re-register" msgid "Re-register Email Domain" msgstr "Re-register Email Domain" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "Re-Sync fehlgeschlagen" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7989,8 +8572,8 @@ msgid "Read Only" msgstr "Read Only" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Read our documentation to get started with NexaSign." +msgid "Read our documentation to get started with NexaFile." +msgstr "Read our documentation to get started with NexaFile." #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8009,6 +8592,14 @@ msgstr "Reading your document" msgid "Ready" msgstr "Ready" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "Reaktivieren" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "Reaktivieren fehlgeschlagen" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8047,6 +8638,11 @@ msgstr "Recent activity" msgid "Recent documents" msgstr "Recent documents" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "Rechnungs-Nr." + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8533,6 +9129,10 @@ msgstr "Restricted Access" msgid "Retention of Documents" msgstr "Retention of Documents" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "Retention-Check und Löschschutz" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Retried" @@ -8564,8 +9164,8 @@ msgid "Return to Home" msgstr "Return to Home" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Return to NexaSign sign in page here" +msgid "Return to NexaFile sign in page here" +msgstr "Return to NexaFile sign in page here" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9234,6 +9834,22 @@ msgstr "Sign Up with Microsoft" msgid "Sign Up with OIDC" msgstr "Sign Up with OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "Signatur-Dokument geöffnet" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "Signatur-Dokument konnte nicht vorbereitet werden" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "Signatur-Dokument öffnen" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "Signatur-Dokument vorbereitet" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9417,8 +10033,12 @@ msgid "Skip" msgstr "Skip" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." -msgstr "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "So könnte Ihr öffentliches NexaFile-Profil aussehen." + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." +msgstr "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx msgid "Some signers have not been assigned a signature field. Please assign at least 1 signature field to each signer before proceeding." @@ -9568,10 +10188,22 @@ msgstr "Space-separated list of domains. Leave empty to allow all domains." msgid "Spanish" msgstr "Spanish" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "Speichern fehlgeschlagen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "Speichern und synchronisieren" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Stats" @@ -9587,6 +10219,7 @@ msgstr "Stats" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9749,6 +10382,14 @@ msgstr "Successfully created passkey" msgid "Successfully created: {successCount}" msgstr "Successfully created: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "Suchbegriff" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "Suchen…" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Summary:" @@ -9785,6 +10426,18 @@ msgstr "Sync failed, changes not saved" msgid "Sync license from server" msgstr "Sync license from server" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "Sync-Lauf gestartet" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "Sync-Lauf konnte nicht starten" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "Sync-Lauf starten" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9809,14 +10462,15 @@ msgstr "Target Organisation" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Team" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "Team \"{0}\" has been deleted on NexaSign" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "Team \"{0}\" has been deleted on NexaFile" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9826,6 +10480,10 @@ msgstr "Team Admin" msgid "Team Assignments" msgstr "Team Assignments" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "Team auswählen" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9867,8 +10525,8 @@ msgid "Team email removed" msgstr "Team email removed" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "Team email removed for {teamName} on NexaSign" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "Team email removed for {teamName} on NexaFile" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10082,7 +10740,6 @@ msgid "Template uploaded" msgstr "Template uploaded" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10103,6 +10760,11 @@ msgstr "Templates partially deleted" msgid "Test" msgstr "Test" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "Test fehlgeschlagen" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Test Webhook" @@ -10153,8 +10815,8 @@ msgid "Thank you for completing the signing process." msgstr "Thank you for completing the signing process." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10517,8 +11179,8 @@ msgstr "The types of signatures that recipients are allowed to use when signing #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "The URL for NexaSign to send webhook events to." +msgid "The URL for NexaFile to send webhook events to." +msgstr "The URL for NexaFile to send webhook events to." #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10662,8 +11324,8 @@ msgid "This document has been signed by all recipients" msgstr "This document has been signed by all recipients" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10682,8 +11344,8 @@ msgid "This document was created using a direct link." msgstr "This document was created using a direct link." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." -msgstr "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." +msgstr "This document was sent using NexaFile." #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx msgid "This document will be duplicated." @@ -10899,6 +11561,10 @@ msgstr "Title" msgid "Title cannot be empty" msgstr "Title cannot be empty" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "TLS-Zertifikat prüfen" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "To accept this invitation you must create an account." @@ -11342,6 +12008,10 @@ msgstr "Unpin" msgid "Unsealed Documents" msgstr "Unsealed Documents" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "Unterzeichnen" @@ -11722,6 +12392,37 @@ msgstr "Validation failed" msgid "Value" msgstr "Value" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "Verarbeitet" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "Verbinden Sie Ihre erste Dokumentenquelle" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "Verbindung erfolgreich" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "Verbindung fehlgeschlagen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "Verbindung testen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "Vergangene Sync-Läufe" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Verification Code Required" @@ -11777,6 +12478,10 @@ msgstr "Vertical" msgid "Vertical Align" msgstr "Vertical Align" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "Vertragsvorlagen für deutsche Unternehmen" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11958,6 +12663,27 @@ msgstr "Viewing" msgid "Visibility" msgstr "Visibility" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "Von" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "Vorlagen" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "Vorletztes Jahr" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "Waiting" @@ -11981,8 +12707,8 @@ msgstr "Waiting for Your Turn" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "Want to send slick signing links like this one? <0>Check out NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "Want to send slick signing links like this one? <0>Check out NexaFile." #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12000,6 +12726,22 @@ msgstr "Want your own public profile?" msgid "Warning: Assistant as last signer" msgstr "Warning: Assistant as last signer" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "Wartet auf ersten Sync" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "Was ist GoBD überhaupt?" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "Was NexaFile liefert" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "Was Sie selbst regeln" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12410,8 +13152,8 @@ msgid "Welcome to {organisationName}" msgstr "Welcome to {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "Welcome to NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "Welcome to NexaFile!" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12449,8 +13191,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "Whether to enable the SSO portal for your organisation" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12465,6 +13207,10 @@ msgstr "Who do you want to remind?" msgid "Width:" msgstr "Width:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "Wird abgebrochen…" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Withdrawing Consent" @@ -12705,8 +13451,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "You can only detect fields in draft envelopes" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "You can revoke access at any time in your team settings on NexaSign <0>here." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "You can revoke access at any time in your team settings on NexaFile <0>here." #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12850,8 +13596,8 @@ msgstr "You have been invited by <0>{0} to join their organisation." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "You have been invited to join {0} on NexaSign" +msgid "You have been invited to join {0} on NexaFile" +msgstr "You have been invited to join {0} on NexaFile" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13401,12 +14147,12 @@ msgid "Your Email" msgstr "Your Email" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "Your email has already been confirmed. You can now use all features of NexaSign." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "Your email has already been confirmed. You can now use all features of NexaFile." #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "Your email has been successfully confirmed! You can now use all features of NexaSign." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "Your email has been successfully confirmed! You can now use all features of NexaFile." #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13474,8 +14220,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Your plan does not support inviting members. Please upgrade or your plan or contact sales at <0>{SUPPORT_EMAIL} if you would like to discuss your options." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13575,3 +14321,19 @@ msgstr "Your verification code:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "Zeitraum prüfen" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "Zum Signieren vorbereiten" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "Zurück" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "Zurück zur Liste" diff --git a/packages/lib/translations/es/web.po b/packages/lib/translations/es/web.po index 209c2dc..52d7081 100644 --- a/packages/lib/translations/es/web.po +++ b/packages/lib/translations/es/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, one {Estás a punto de eliminar la plantilla seleccionada.} msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "Campo {0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} te ha invitado a {recipientActionVerb} el documento \"{1}\"." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0} en nombre de \"{1}\" te ha invitado a {recipientActionVerb} el docum msgid "{0} Teams" msgstr "{0} Equipos" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} en {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {1 carácter restante} other {{charactersRemaining} caracteres restantes}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {Este código expirará en # minuto.} other {Este código expirará en # minutos.}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference} ha firmado {documentName}" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {# carácter restante} other {# caracteres restantes}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount} seleccionado(s)" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} ha solicitado crear una cuenta en tu nombre." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} ha solicitado vincular tu cuenta actual de NexaSign a su organización." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail}, en nombre de \"{0}\", te ha invitado a ver este documento" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} ha solicitado usar tu dirección de correo electrónico para su equipo en NexaSign." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>Todos - Todos pueden acceder y ver el documento" msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Acceso completo a la cuenta: Ve toda tu información de perfil, configuración y actividad" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Heredar método de autenticación - Use el método de autenticación de firma de acción global configurado en el paso \"Configuración General\"" @@ -790,6 +821,10 @@ msgstr "1 organizaciones gratuitas restantes" msgid "1 month" msgstr "1 mes" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 meses" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "Un medio para imprimir o descargar documentos para sus registros" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "Un miembro se ha unido a tu organización en NexaSign" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "Un miembro ha dejado tu organización {organisationName}" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "Un miembro ha dejado tu organización en NexaSign" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "Se ha hecho una solicitud para crear una cuenta para ti" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "Se ha hecho una solicitud para vincular tu cuenta de NexaSign" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "Se ha iniciado una solicitud para usar tu correo electrónico por {0} en NexaSign" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "Un secreto que se enviará a tu URL para que puedas verificar que la solicitud ha sido enviada por NexaSign." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "Se requiere un correo electrónico válido" msgid "A verification email will be sent to the provided email." msgstr "Se enviará un correo electrónico de verificación a la dirección proporcionada." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "Aceptar y Vincular Cuenta" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Aceptar invitación para unirse a una organización en NexaSign" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Aceptar la solicitud de correo electrónico del equipo para {teamName} en NexaSign" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "Funciones de IA" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "Las funciones de IA están desactivadas para tu equipo. Pide a la persona propietaria del equipo u organización que las habilite." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "Todas las plantillas" msgid "All Time" msgstr "Todo el Tiempo" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Permitir a todos los miembros de la organización acceder a este equipo" @@ -1576,6 +1666,14 @@ msgstr "Casi listo" msgid "Already have an account? <0>Sign in instead" msgstr "¿Ya tienes una cuenta? <0>Iniciar sesión en su lugar" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Cantidad" @@ -1889,6 +1987,19 @@ msgstr "Analizando el diseño de la página" msgid "Analyzing pages" msgstr "Analizando las páginas" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Cualquier documento al que hayas sido invitado aparecerá aquí" @@ -1913,6 +2024,10 @@ msgstr "Tokens de API" msgid "App Version" msgstr "Versión de la Aplicación" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "Aprobando" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "¿Estás seguro de que quieres completar el documento? Esta acción no se puede deshacer. Por favor, asegúrate de haber completado todos los campos relevantes antes de continuar." @@ -2116,6 +2244,10 @@ msgstr "Detalles del registro de auditoría" msgid "Audit Logs" msgstr "Registros de Auditoría" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "Códigos de respaldo" msgid "Banner Updated" msgstr "Banner actualizado" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Antes de comenzar, por favor confirma tu dirección de correo electrónico haciendo clic en el botón de abajo:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "Facturación" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Negro" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "Al habilitar 2FA, se te requerirá ingresar un código de tu aplicación de autenticación cada vez que inicies sesión usando email y contraseña." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "Al continuar utilizando el servicio de firma electrónica proporcionado por NexaSign, usted afirma que ha leído y entendido esta divulgación. Acepta todos los términos y condiciones relacionados con el uso de firmas electrónicas y transacciones electrónicas según lo detallado aquí." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "Creando documento" msgid "Creating Template" msgstr "Creando plantilla" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "Estructura CSV" @@ -3338,6 +3535,10 @@ msgstr "Grupos de Organización Personalizados" msgid "Dark Mode" msgstr "Modo Oscuro" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "Formato de fecha" msgid "Date Settings" msgstr "Configuración de Fecha" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David es el empleado, Lucas es el gerente" @@ -3625,11 +3834,20 @@ msgstr "Eliminado" msgid "Deleting account..." msgstr "Eliminando cuenta..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Destino" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "Dispositivo" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "¿No solicitaste un cambio de contraseña? Estamos aquí para ayudarte a asegurar tu cuenta, solo <0>contáctanos." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "Documentación" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "Documentos en los que todos los destinatarios han firmado pero el docume msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "Dibujar" msgid "Draw signature" msgstr "Dibujar firma" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "Suelta el PDF aquí o haz clic para seleccionarlo" @@ -4433,10 +4690,22 @@ msgstr "Plantilla Duplicada" msgid "Duplicate values are not allowed" msgstr "No se permiten valores duplicados" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "Neerlandés" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "p. ej., Legal" msgid "eg. Mac" msgstr "p. ej., Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Entrega Electrónica de Documentos" @@ -4800,6 +5077,10 @@ msgstr "Documento Adjunto" msgid "Enclosed Documents" msgstr "Documentos adjuntos" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "Inglés" @@ -4906,6 +5187,10 @@ msgstr "Ingresa tu texto aquí" msgid "Enterprise" msgstr "Enterprise" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Sobre distribuido" @@ -4952,6 +5237,14 @@ msgstr "Título del Sobre" msgid "Envelope updated" msgstr "Sobre actualizado" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "Error al cargar la página" msgid "Error uploading file" msgstr "Error al cargar el archivo" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "Expira en {0}" msgid "Expires on {0}" msgstr "Expira el {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "ID externo" msgid "Extracting contact details" msgstr "Extrayendo datos de contacto" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "Flags de características" msgid "Features" msgstr "Funciones" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Límite de caracteres del campo" @@ -5337,6 +5650,10 @@ msgstr "Rellena los detalles para crear una nueva reclamación de suscripción." msgid "Filter by status" msgstr "Filtrar por estado" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "Francés" msgid "Full Name" msgstr "Nombre completo" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "Generar enlaces" msgid "German" msgstr "Alemán" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Autenticación de acción de destinatario global" @@ -5556,6 +5890,22 @@ msgstr "Ir al equipo" msgid "Go to your <0>public profile settings to add documents." msgstr "Ve a tu <0>configuración de perfil público para agregar documentos." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Verde" @@ -5686,6 +6036,14 @@ msgstr "Ocultar" msgid "Hide license key" msgstr "Ocultar clave de licencia" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "Horizontal" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "Tiempo que tienen los destinatarios para completar este documento después de que se envía. Usa el valor predeterminado del equipo cuando está configurado como heredado." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "Acepto vincular mi cuenta con esta organización" @@ -5790,10 +6152,41 @@ msgstr "Si no encuentras el enlace de confirmación en tu bandeja de entrada, pu msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "Si tu aplicación de autenticación no admite códigos QR, puedes usar el siguiente código en su lugar:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Importante: Lo que esto significa" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "Incluye:" msgid "Information" msgstr "Información" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Heredar método de autenticación" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "Clave de licencia no válida" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "Tipo de licencia no válido: tu instancia de NexaSign está usando funciones que no forman parte de tu licencia." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "Japonés" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Únete a {organisationName} en NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "Unido" msgid "Joined {0}" msgstr "Se unió a {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "Identificadores clave y relaciones para este equipo." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "Coreano" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "Coreano" msgid "Label" msgstr "Etiqueta" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "Espaciado de letras" msgid "Letter Spacing" msgstr "Espaciado de letras" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "Modo claro" msgid "Like to have your own public profile with agreements?" msgstr "¿Te gustaría tener tu propio perfil público con acuerdos?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Altura de línea" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "Vincular plantilla" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Vincula tu cuenta de NexaSign" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "Buscando campos de formulario" msgid "Looking for signature fields" msgstr "Buscando campos de firma" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "Gerente" msgid "Managers and above" msgstr "Gerentes y superiores" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Asignando campos a destinatarios" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "Mín" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "Licencia faltante: tu instancia de NexaSign está usando funciones que requieren una licencia." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "Mi Carpeta" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "Necesita firmar" msgid "Needs to view" msgstr "Necesita ver" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Nunca" @@ -6791,13 +7267,21 @@ msgstr "Nueva opción {0}" msgid "New Password" msgstr "Nueva Contraseña" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "Licencia de NexaSign" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign eliminará <0>todos sus documentos, junto con todos sus documentos completados, firmas y todos los demás recursos de su cuenta." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "No se encontró valor." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "¡No te preocupes, sucede! Ingresa tu correo electrónico y te enviaremos un enlace especial para restablecer tu contraseña." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "Número de equipos permitidos. 0 = Ilimitado" msgid "Number Settings" msgstr "Configuración de Número" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "Desactivado" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "Activado" @@ -7545,6 +8049,10 @@ msgstr "Invitaciones pendientes de la organización" msgid "Pending since" msgstr "Pendiente desde" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "Cuenta personal" msgid "Personal Inbox" msgstr "Bandeja de entrada personal" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "Por favor, suba un logotipo" msgid "Polish" msgstr "Polaco" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "Portugués (Brasil)" @@ -7824,6 +8344,14 @@ msgstr "Pos. X:" msgid "Pos Y:" msgstr "Pos. Y:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "Plantilla pública" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Las plantillas públicas están conectadas a tu perfil público. Cualquier modificación a las plantillas públicas también aparecerá en tu perfil público." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Acciones rápidas" @@ -7980,6 +8558,11 @@ msgstr "Volver a registrar" msgid "Re-register Email Domain" msgstr "Volver a registrar dominio de correo electrónico" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "Solo lectura" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Lea nuestra documentación para comenzar con NexaSign." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "Leyendo tu documento" msgid "Ready" msgstr "Listo" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "Actividad reciente" msgid "Recent documents" msgstr "Documentos recientes" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "Acceso restringido" msgid "Retention of Documents" msgstr "Retención de Documentos" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Reintentado" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "Regresar a la página de inicio" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Regrese a la página de inicio de sesión de NexaSign aquí" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "Registrarse con Microsoft" msgid "Sign Up with OIDC" msgstr "Regístrate con OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "Omitir" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "Lista de dominios separados por espacios. Deje vacío para permitir todo msgid "Spanish" msgstr "Español" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Estadísticas" @@ -9592,6 +10224,7 @@ msgstr "Estadísticas" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "Clave de acceso creada con éxito" msgid "Successfully created: {successCount}" msgstr "Creado con éxito: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Resumen:" @@ -9790,6 +10431,18 @@ msgstr "La sincronización falló, los cambios no se guardaron" msgid "Sync license from server" msgstr "Sincronizar licencia desde el servidor" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "Organización de destino" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Equipo" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "El equipo \"{0}\" ha sido eliminado en NexaSign" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "Administrador del equipo" msgid "Team Assignments" msgstr "Asignaciones de equipo" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "Correo electrónico del equipo eliminado" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "Correo electrónico del equipo eliminado para {teamName} en NexaSign" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "Plantilla subida" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "Plantillas eliminadas parcialmente" msgid "Test" msgstr "Probar" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Prueba de Webhook" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "Gracias por completar el proceso de firma." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Gracias por usar NexaSign para realizar su firma electrónica de documentos. El propósito de esta divulgación es informarle sobre el proceso, la legalidad y sus derechos con respecto al uso de firmas electrónicas en nuestra plataforma. Al optar por usar una firma electrónica, usted está aceptando los términos y condiciones descritos a continuación." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "Los tipos de firmas que los destinatarios pueden usar al firmar el docum #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "La URL para NexaSign para enviar eventos de webhook." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "Este documento ha sido firmado por todos los destinatarios" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "Este documento está disponible en tu cuenta de NexaSign. Puedes ver más detalles, destinatarios y registros de auditoría allí." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "Este documento fue creado usando un enlace directo." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "Título" msgid "Title cannot be empty" msgstr "El título no puede estar vacío" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "Para aceptar esta invitación debes crear una cuenta." @@ -11347,6 +12013,10 @@ msgstr "Desanclar" msgid "Unsealed Documents" msgstr "Documentos sin sellar" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "Validación fallida" msgid "Value" msgstr "Valor" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Código de verificación requerido" @@ -11782,6 +12483,10 @@ msgstr "Vertical" msgid "Vertical Align" msgstr "Alineación vertical" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "Viendo" msgid "Visibility" msgstr "Visibilidad" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "Esperando" @@ -11986,8 +12712,8 @@ msgstr "Esperando tu turno" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "¿Quieres enviar enlaces de firma tan elegantes como este? <0>Prueba NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "¿Quieres tu propio perfil público?" msgid "Warning: Assistant as last signer" msgstr "Advertencia: Asistente como último firmante" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "Bienvenido a {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "¡Bienvenido a NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "Si desea habilitar el portal de SSO para su organización" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "Mientras esperas a que ellos lo hagan, puedes crear tu propia cuenta de NexaSign y comenzar a firmar documentos de inmediato." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "¿A quién deseas recordar?" msgid "Width:" msgstr "Ancho:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Retirar Consentimiento" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "Solo puedes detectar campos en sobres en borrador" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "Puedes revocar el acceso en cualquier momento en la configuración de tu equipo en NexaSign <0>aquí." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "Has sido invitado por <0>{0} para unirte a su organización." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "Te han invitado a unirte a {0} en NexaSign" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "Tu correo electrónico" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "Tu correo electrónico ya ha sido confirmado. Ahora puedes usar todas las funciones de NexaSign." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "¡Tu correo electrónico ha sido confirmado con éxito! Ahora puedes usar todas las funciones de NexaSign." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Tu plan no soporta invitar miembros. Por favor, actualiza tu plan o contacta con ventas en <0>{SUPPORT_EMAIL} si deseas hablar sobre tus opciones." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Tu plan ya no es válido. Por favor, suscríbete a un nuevo plan para continuar usando NexaSign." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "Su código de verificación:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "su-dominio.com otro-dominio.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/fr/web.po b/packages/lib/translations/fr/web.po index f5e6a1b..9dd8da4 100644 --- a/packages/lib/translations/fr/web.po +++ b/packages/lib/translations/fr/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, one {Vous êtes sur le point de supprimer le modèle sélect msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "champ {0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} vous a invité à {recipientActionVerb} le document \"{1}\"." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0} représentant \"{1}\" vous a invité à {recipientActionVerb} le doc msgid "{0} Teams" msgstr "{0} Équipes" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} sur {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {1 caractère restant} other {{charactersRemaining} caractères restants}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {Ce code expirera dans # minute.} other {Ce code expirera dans # minutes.}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference} a signé {documentName}" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {# caractère restant} other {# caractères restants}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount} sélectionné(s)" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} a demandé à créer un compte en votre nom." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} a demandé à lier votre compte NexaSign actuel à son organisation." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail}, au nom de \"{0}\", vous a invité à voir ce document" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} a demandé à utiliser votre adresse e-mail pour leur équipe sur NexaSign." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>Tout le monde - Tout le monde peut accéder au document et le voi msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Accès complet au compte : Consultez toutes vos informations de profil, paramètres, et activités" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Hériter de la méthode d'authentification - Utilisez la méthode globale d'authentification de signature d'action configurée dans l'étape \"Paramètres généraux\"" @@ -790,6 +821,10 @@ msgstr "1 organisme gratuit restant" msgid "1 month" msgstr "1 mois" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 mois" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "Un moyen d'imprimer ou de télécharger des documents pour vos dossiers" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "Un membre a rejoint votre organisation sur NexaSign" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "Un membre a quitté votre organisation {organisationName}" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "Un membre a quitté votre organisation sur NexaSign" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "Une demande a été effectuée pour créer un compte pour vous" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "Une demande a été effectuée pour lier votre compte NexaSign" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "Une demande pour l'utiliser votre e-mail a été initiée par {0} sur NexaSign" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "Un secret qui sera envoyé à votre URL afin que vous puissiez vérifier que la demande a été envoyée par NexaSign." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "Une adresse e-mail valide est requise" msgid "A verification email will be sent to the provided email." msgstr "Un e-mail de vérification sera envoyé à l'adresse e-mail fournie." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "Accepter & Lier le Compte" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Accepter l'invitation à rejoindre une organisation sur NexaSign" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Accepter la demande d'e-mail de l'équipe pour {teamName} sur NexaSign" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "Fonctionnalités IA" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "Les fonctionnalités d’IA sont désactivées pour votre équipe. Veuillez demander au propriétaire de votre équipe ou de votre organisation de les activer." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "Tous les modèles" msgid "All Time" msgstr "Depuis toujours" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Permettre à tous les membres de l'organisation d'accéder à cette équipe" @@ -1576,6 +1666,14 @@ msgstr "Presque terminé" msgid "Already have an account? <0>Sign in instead" msgstr "Vous avez déjà un compte ? <0>Connectez-vous plutôt" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Montant" @@ -1889,6 +1987,19 @@ msgstr "Analyse de la mise en page" msgid "Analyzing pages" msgstr "Analyse des pages" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Tous les documents auxquels vous avez été invité apparaîtront ici" @@ -1913,6 +2024,10 @@ msgstr "Tokens API" msgid "App Version" msgstr "Version de l'application" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "En attente d'approbation" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "Êtes-vous sûr de vouloir finaliser le document ? Cette action ne peut être annulée. Veuillez vous assurer d'avoir pré-rempli tous les champs pertinents avant de continuer." @@ -2116,6 +2244,10 @@ msgstr "Détails du journal d’audit" msgid "Audit Logs" msgstr "Journaux de vérification" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "Codes de sauvegarde" msgid "Banner Updated" msgstr "Bannière mise à jour" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Avant de commencer, veuillez confirmer votre adresse e-mail en cliquant sur le bouton ci-dessous :" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "Facturation" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Noir" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "En activant l'authentification à deux facteurs, vous devrez entrer un code de votre application d'authentification à chaque fois que vous vous connectez avec votre mot de passe par email." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "En procédant à l'utilisation du service de signature électronique fourni par NexaSign, vous affirmez avoir lu et compris cette divulgation. Vous acceptez tous les termes et conditions liés à l'utilisation des signatures électroniques et des transactions électroniques comme décrit ici." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "Création du document" msgid "Creating Template" msgstr "Création du modèle" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "Structure CSV" @@ -3338,6 +3535,10 @@ msgstr "Groupes d'organisation personnalisés" msgid "Dark Mode" msgstr "Mode sombre" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "Format de date" msgid "Date Settings" msgstr "Paramètres de la date" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David est l'employé, Lucas est le manager" @@ -3625,11 +3834,20 @@ msgstr "Supprimé" msgid "Deleting account..." msgstr "Suppression du compte..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Destination" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "Appareil" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "Vous n'avez pas demandé de changement de mot de passe ? Nous sommes là pour vous aider à sécuriser votre compte, il vous suffit de <0>nous contacter." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "Documentation" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "Documents pour lesquels tous les destinataires ont signé mais qui n’o msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "Dessiner" msgid "Draw signature" msgstr "Dessiner la signature" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "Déposez le PDF ici ou cliquez pour en sélectionner un" @@ -4433,10 +4690,22 @@ msgstr "Dupliquer le modèle" msgid "Duplicate values are not allowed" msgstr "Les valeurs en double ne sont pas autorisées" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "Néerlandais" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "par ex. Juridique" msgid "eg. Mac" msgstr "par ex. Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Remise électronique de documents" @@ -4800,6 +5077,10 @@ msgstr "Document joint" msgid "Enclosed Documents" msgstr "Documents joints" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "Anglais" @@ -4906,6 +5187,10 @@ msgstr "Entrez votre texte ici" msgid "Enterprise" msgstr "Entreprise" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Enveloppe distribuée" @@ -4952,6 +5237,14 @@ msgstr "Titre de l'enveloppe" msgid "Envelope updated" msgstr "Enveloppe mise à jour" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "Erreur lors du chargement de la page" msgid "Error uploading file" msgstr "Erreur lors de l'importation du fichier" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "Expire dans {0}" msgid "Expires on {0}" msgstr "Expire le {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "ID externe" msgid "Extracting contact details" msgstr "Extraction des coordonnées" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "Drapeaux de fonctionnalités" msgid "Features" msgstr "Fonctionnalités" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Limite de caractères du champ" @@ -5337,6 +5650,10 @@ msgstr "Remplissez les détails pour créer une nouvelle réclamation d'abonneme msgid "Filter by status" msgstr "Filtrer par statut" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "Français" msgid "Full Name" msgstr "Nom complet" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "Générer des liens" msgid "German" msgstr "Allemand" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Authentification d'action de destinataire globale" @@ -5556,6 +5890,22 @@ msgstr "Aller à l'équipe" msgid "Go to your <0>public profile settings to add documents." msgstr "Allez à vos <0>paramètres de profil public pour ajouter des documents." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Vert" @@ -5686,6 +6036,14 @@ msgstr "Cacher" msgid "Hide license key" msgstr "Masquer la clé de licence" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "Horizontal" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "Durée pendant laquelle les destinataires disposent pour compléter ce document après son envoi. Utilise la valeur par défaut de l’équipe lorsque le mode hérité est sélectionné." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "J'accepte de lier mon compte avec cette organisation" @@ -5790,10 +6152,41 @@ msgstr "Si vous ne trouvez pas le lien de confirmation dans votre boîte de réc msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "Si votre application d'authentification ne prend pas en charge les codes QR, vous pouvez utiliser le code suivant à la place :" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Important : Ce que cela signifie" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "Comprenda0:" msgid "Information" msgstr "Information" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Hériter de la méthode d'authentification" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "Clé de licence invalide" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "Type de licence invalide - Votre instance NexaSign utilise des fonctionnalités qui ne font pas partie de votre licence." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "Japonais" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Rejoindre {organisationName} sur NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "Joint" msgid "Joined {0}" msgstr "A rejoint {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "Identifiants clés et relations pour cette équipe." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "Coréen" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "Coréen" msgid "Label" msgstr "Étiquette" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "Espacement des lettres" msgid "Letter Spacing" msgstr "Espacement des Lettres" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "Mode clair" msgid "Like to have your own public profile with agreements?" msgstr "Vous voulez avoir votre propre profil public avec des accords ?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Hauteur de ligne" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "Lier le modèle" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Liez votre compte NexaSign" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "Recherche de champs de formulaire" msgid "Looking for signature fields" msgstr "Recherche de champs de signature" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "Gestionnaire" msgid "Managers and above" msgstr "Responsables et supérieur" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Association des champs aux destinataires" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "Min" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "Licence manquante - Votre instance NexaSign utilise des fonctionnalités qui nécessitent une licence." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "Mon Dossier" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "Nécessite une signature" msgid "Needs to view" msgstr "Nécessite une visualisation" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Jamais" @@ -6791,13 +7267,21 @@ msgstr "Nouvelle option {0}" msgid "New Password" msgstr "Nouveau Mot de Passe" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "Licence NexaSign" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign supprimera <0>tous vos documents, ainsi que tous vos documents complétés, signatures, et toutes les autres ressources appartenant à votre compte." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "Aucune valeur trouvée." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "Pas de soucis, ça arrive ! Entrez votre email et nous vous enverrons un lien spécial pour réinitialiser votre mot de passe." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "Nombre d'équipes autorisées. 0 = Illimité" msgid "Number Settings" msgstr "Paramètres du nombre" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "Désactivé" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "Activé" @@ -7545,6 +8049,10 @@ msgstr "Invitations à l’organisation en attente" msgid "Pending since" msgstr "En attente depuis" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "Compte personnel" msgid "Personal Inbox" msgstr "Boîte de réception personnelle" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "Veuillez télécharger un logo" msgid "Polish" msgstr "Polonais" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "Portugais (Brésil)" @@ -7824,6 +8344,14 @@ msgstr "Pos X :" msgid "Pos Y:" msgstr "Pos Y :" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "Modèle Public" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Les modèles publics sont connectés à votre profil public. Toute modification apportée aux modèles publics apparaîtra également dans votre profil public." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Actions Rapides" @@ -7980,6 +8558,11 @@ msgstr "Réinscrire" msgid "Re-register Email Domain" msgstr "Réinscrire le domaine e-mail" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "Lecture Seule" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Lisez notre documentation pour commencer avec NexaSign." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "Lecture de votre document" msgid "Ready" msgstr "Prêt" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "Activité récente" msgid "Recent documents" msgstr "Documents récents" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "Accès restreint" msgid "Retention of Documents" msgstr "Conservation des documents" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Réessayé" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "Retour à l'accueil" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Revenir à la page de connexion de NexaSign ici" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "S'inscrire avec Microsoft" msgid "Sign Up with OIDC" msgstr "S'inscrire avec OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "Ignorer" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "Liste des domaines séparée par des espaces. Laissez vide pour autorise msgid "Spanish" msgstr "Espagnol" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Statistiques" @@ -9592,6 +10224,7 @@ msgstr "Statistiques" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "Clé d'authentification créée avec succès" msgid "Successfully created: {successCount}" msgstr "Créés avec succès : {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Résumé :" @@ -9790,6 +10431,18 @@ msgstr "Échec de la synchronisation, modifications non enregistrées" msgid "Sync license from server" msgstr "Synchroniser la licence depuis le serveur" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "Organisation cible" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Équipe" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "L'équipe \"{0}\" a été supprimée sur NexaSign" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "Admin de l'équipe" msgid "Team Assignments" msgstr "Affectations de l'équipe" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "Email d'équipe supprimé" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "Email d'équipe supprimé pour {teamName} sur NexaSign" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "Modèle de document téléchargé" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "Modèles partiellement supprimés" msgid "Test" msgstr "Test" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Test du webhook" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "Merci d'avoir complété le processus de signature." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Merci d'utiliser NexaSign pour signer vos documents électroniquement. L'objectif de cette clause est de vous informer sur le processus, la légalité et vos droits concernant l'utilisation de la signature électronique sur notre plateforme. En choisissant d'utiliser un sytème de signature électronique, vous acceptez les termes et conditions exposés ci-dessous." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "Les types de signatures que les destinataires peuvent utiliser lors de l #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "L'URL pour NexaSign pour envoyer des événements webhook." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "Ce document a été signé par tous les destinataires" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "Ce document est disponible dans votre compte NexaSign. Vous pouvez y voir plus de détails, destinataires, et journaux d'audit." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "Ce document a été créé en utilisant un lien direct." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "Titre" msgid "Title cannot be empty" msgstr "Le titre ne peut pas être vide" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "Pour accepter cette invitation, vous devez créer un compte." @@ -11347,6 +12013,10 @@ msgstr "Détacher" msgid "Unsealed Documents" msgstr "Documents non scellés" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "La validation a échoué" msgid "Value" msgstr "Valeur" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Code de vérification requis" @@ -11782,6 +12483,10 @@ msgstr "Vertical" msgid "Vertical Align" msgstr "Alignement Vertical" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "Consultation" msgid "Visibility" msgstr "Visibilité" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "En attente" @@ -11986,8 +12712,8 @@ msgstr "En attente de votre tour" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "Vous voulez envoyer des liens de signature aussi soignés que celui-ci ? <0>Découvrez NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "Vous voulez votre propre profil public ?" msgid "Warning: Assistant as last signer" msgstr "Avertissement : Assistant comme dernier signataire" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "Bienvenue chez {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "Bienvenue sur NexaSign !" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "S'il est judicieux d'activer le portail SSO pour votre organisation" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "En attendant qu'ils le fassent, vous pouvez créer votre propre compte NexaSign et commencer à signer des documents dès maintenant." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "Qui voulez-vous rappeler ?" msgid "Width:" msgstr "Largeur :" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Retrait du consentement" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "Vous pouvez uniquement détecter les champs dans les enveloppes brouillon" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "Vous pouvez révoquer l’accès à tout moment dans les paramètres de votre équipe sur NexaSign <0>ici." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "Vous avez été invité par <0>{0} à rejoindre leur organisation." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "Vous avez été invité à rejoindre {0} sur NexaSign" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "Votre Email" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "Votre email a déjà été confirmé. Vous pouvez maintenant utiliser toutes les fonctionnalités de NexaSign." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "Votre e-mail a été confirmé avec succès ! Vous pouvez maintenant utiliser toutes les fonctionnalités de NexaSign." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Votre abonnement n'inclut pas l'invitation de membres. Veuillez modifier votre abonnement ou contacter le service commercial à <0>{SUPPORT_EMAIL} si vous souhaitez discuter de vos options." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Votre abonnement n'est plus valide. Veuillez souscrire à un nouvel abonnement pour continuer à utiliser NexaSign." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "Votre code de vérification :" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/it/web.po b/packages/lib/translations/it/web.po index 8976ef7..9fafcbe 100644 --- a/packages/lib/translations/it/web.po +++ b/packages/lib/translations/it/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, one {Stai per eliminare il modello selezionato.} other {Stai msgid "{0}" msgstr "" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "Campo {0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} ti ha invitato a {recipientActionVerb} il documento \"{1}\"." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0} per conto di \"{1}\" ti ha invitato a {recipientActionVerb} il docum msgid "{0} Teams" msgstr "{0} Squadre" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} su {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {1 carattere rimanente} other {{charactersRemaining} caratteri rimanenti}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {Questo codice scadrà in # minuto.} other {Questo codice scadrà in # minuti.}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference} ha firmato {documentName}" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {# carattere rimanente} other {# caratteri rimanenti}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount} selezionati" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} ha richiesto di creare un account per tuo conto." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} ha richiesto di collegare il tuo account NexaSign attuale alla loro organizzazione." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail}, per conto di \"{0}\", ti ha invitato a visualizzare questo documento" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} ha richiesto di utilizzare il tuo indirizzo email per il loro team su NexaSign." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>Chiunque - Chiunque può accedere e visualizzare il documento" msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Accesso completo all'account: Visualizza tutte le informazioni sul tuo profilo, le impostazioni e l'attività" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Eredita metodo di autenticazione - Usa il metodo globale di autenticazione della firma configurato nel passaggio \"Impostazioni generali\"" @@ -790,6 +821,10 @@ msgstr "1 Organizzazione gratuita rimasta" msgid "1 month" msgstr "{VAR_PLURAL, select, one {1 mese} other {# mesi}}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "{VAR_PLURAL, select, one {1 mese} other {12 mesi}}" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "Un mezzo per stampare o scaricare documenti per i tuoi archivi" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "Un membro si è unito alla tua organizzazione su NexaSign" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "Un membro ha lasciato la tua organizzazione {organisationName}" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "Un membro ha lasciato la tua organizzazione su NexaSign" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "È stata effettuata una richiesta per creare un account per te" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "È stata effettuata una richiesta per collegare il tuo account NexaSign" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "Una richiesta per utilizzare la tua email è stata avviata da {0} su NexaSign" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "Un codice segreto che verrà inviato al tuo URL in modo che tu possa verificare che la richiesta sia stata inviata da NexaSign." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "È richiesta un'email valida" msgid "A verification email will be sent to the provided email." msgstr "Un'email di verifica sarà inviata all'email fornita." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "Accetta & Collega Account" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Accetta l'invito a unirti a un'organizzazione su NexaSign" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Accetta la richiesta di email per il team {teamName} su NexaSign" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "Funzionalità IA" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "Le funzionalità di IA sono disabilitate per il tuo team. Chiedi al proprietario del team o al proprietario dell’organizzazione di abilitarle." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "Tutti i modelli" msgid "All Time" msgstr "Tutto il tempo" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Consenti a tutti i membri dell'organizzazione di accedere a questo team" @@ -1576,6 +1666,14 @@ msgstr "Quasi finito" msgid "Already have an account? <0>Sign in instead" msgstr "Hai già un account? <0>Accedi al posto" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Importo" @@ -1889,6 +1987,19 @@ msgstr "Analisi del layout della pagina in corso" msgid "Analyzing pages" msgstr "Analisi delle pagine in corso" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Tutti i documenti a cui sei stato invitato verranno visualizzati qui" @@ -1913,6 +2024,10 @@ msgstr "Token API" msgid "App Version" msgstr "Versione dell'app" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "In approvazione" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "Sei sicuro di voler completare il documento? Questa azione non può essere annullata. Assicurati di aver completato la precompilazione di tutti i campi rilevanti prima di procedere." @@ -2116,6 +2244,10 @@ msgstr "Dettagli registro di controllo" msgid "Audit Logs" msgstr "Registri di Audit" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "Codici di Backup" msgid "Banner Updated" msgstr "Banner Aggiornato" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Prima di iniziare, conferma il tuo indirizzo email facendo clic sul pulsante qui sotto:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "Fatturazione" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Nero" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "Abilitando la 2FA, ti sarà richiesto di inserire un codice dalla tua app di autenticazione ogni volta che accedi utilizzando email e password." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "Procedendo con l'utilizzo del servizio di firma elettronica fornito da NexaSign, affermi di aver letto e compreso questa divulgazione. Accetti tutti i termini e le condizioni relativi all'uso delle firme elettroniche e delle transazioni elettroniche come descritto in questo documento." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "Creazione del documento" msgid "Creating Template" msgstr "Creazione del modello" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "Struttura CSV" @@ -3338,6 +3535,10 @@ msgstr "Gruppi di Organizzazione Personalizzati" msgid "Dark Mode" msgstr "Modalità Scura" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "Formato data" msgid "Date Settings" msgstr "Impostazioni della data" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David è il dipendente, Lucas è il manager" @@ -3625,11 +3834,20 @@ msgstr "Eliminato" msgid "Deleting account..." msgstr "Eliminazione account..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Destinazione" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "Dispositivo" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "Non hai richiesto una modifica della password? Siamo qui per aiutarti a mettere al sicuro il tuo account, ti basta <0>contattarci." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "Documentazione" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "Documenti in cui tutti i destinatari hanno firmato ma il documento non msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "Disegna" msgid "Draw signature" msgstr "Disegna firma" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "Rilascia qui il PDF o fai clic per selezionarlo" @@ -4433,10 +4690,22 @@ msgstr "Duplica Modello" msgid "Duplicate values are not allowed" msgstr "I valori duplicati non sono ammessi" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "Olandese" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "es. Legale" msgid "eg. Mac" msgstr "es. Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Consegna elettronica dei documenti" @@ -4800,6 +5077,10 @@ msgstr "Documento Allegato" msgid "Enclosed Documents" msgstr "Documenti allegati" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "Inglese" @@ -4906,6 +5187,10 @@ msgstr "Inserisci il tuo testo qui" msgid "Enterprise" msgstr "Impresa" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Busta distribuita" @@ -4952,6 +5237,14 @@ msgstr "Titolo della Busta" msgid "Envelope updated" msgstr "Busta aggiornata" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "Errore durante il caricamento della pagina" msgid "Error uploading file" msgstr "Errore durante il caricamento del file" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "Scade in {0}" msgid "Expires on {0}" msgstr "Scade il {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "ID esterno" msgid "Extracting contact details" msgstr "Estrazione dei dettagli di contatto in corso" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "Flags delle funzionalità" msgid "Features" msgstr "Funzionalità" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Limite di caratteri del campo" @@ -5337,6 +5650,10 @@ msgstr "Compila i dettagli per creare una nuova rivendicazione di abbonamento." msgid "Filter by status" msgstr "Filtra per stato" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "Francese" msgid "Full Name" msgstr "Nome completo" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "Genera link" msgid "German" msgstr "Tedesco" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Autenticazione globale del destinatario" @@ -5556,6 +5890,22 @@ msgstr "Vai al team" msgid "Go to your <0>public profile settings to add documents." msgstr "Vai alle tue <0>impostazioni del profilo pubblico per aggiungere documenti." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Verde" @@ -5686,6 +6036,14 @@ msgstr "Nascondi" msgid "Hide license key" msgstr "Nascondi chiave di licenza" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "Orizzontale" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "Per quanto tempo i destinatari hanno a disposizione per completare questo documento dopo che è stato inviato. Viene utilizzato il valore predefinito del team quando è impostato su eredita." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "Accetto di collegare il mio account con questa organizzazione" @@ -5790,10 +6152,41 @@ msgstr "Se non trovi il link di conferma nella tua casella di posta, puoi richie msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "Se la tua app autenticatrice non supporta i codici QR, puoi usare il seguente codice:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Importante: Cosa Significa" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "Include:" msgid "Information" msgstr "Informazioni" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Ereditare metodo di autenticazione" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "Chiave di licenza non valida" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "Tipo di licenza non valido - La tua istanza NexaSign sta utilizzando funzionalità che non fanno parte della tua licenza." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "Giapponese" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Unisciti a {organisationName} su NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "Iscritto" msgid "Joined {0}" msgstr "Iscritto a {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "Identificatori chiave e relazioni per questo team." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "Coreano" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "Coreano" msgid "Label" msgstr "Etichetta" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "Spaziatura lettere" msgid "Letter Spacing" msgstr "Spaziatura Lettere" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "Modalità chiara" msgid "Like to have your own public profile with agreements?" msgstr "Ti piacerebbe avere il tuo profilo pubblico con accordi?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Interlinea" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "Collega modello" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Collega il tuo account NexaSign" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "Ricerca dei campi del modulo in corso" msgid "Looking for signature fields" msgstr "Ricerca dei campi firma in corso" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "Responsabile" msgid "Managers and above" msgstr "Manager e superiori" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Associazione dei campi ai destinatari in corso" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "Licenza mancante - La tua istanza NexaSign sta utilizzando funzionalità che richiedono una licenza." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "La Mia Cartella" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "Necessita di firma" msgid "Needs to view" msgstr "Necessita di visualizzazione" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Mai" @@ -6791,13 +7267,21 @@ msgstr "Nuova opzione {0}" msgid "New Password" msgstr "Nuova Password" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "Licenza NexaSign" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign eliminerà <0>tutti i tuoi documenti, insieme a tutti i tuoi documenti completati, firme e tutte le altre risorse appartenenti al tuo account." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "Nessun valore trovato." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "Non ti preoccupare, succede! Inserisci la tua email e ti invieremo un link speciale per reimpostare la tua password." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "Numero di team consentiti. 0 = Illimitati" msgid "Number Settings" msgstr "Impostazioni Numero" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "Disattivato" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "Attivato" @@ -7545,6 +8049,10 @@ msgstr "Inviti all’organizzazione in sospeso" msgid "Pending since" msgstr "In sospeso dal" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "Account personale" msgid "Personal Inbox" msgstr "Posta in arrivo personale" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "Si prega di caricare un logo" msgid "Polish" msgstr "Polacco" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "Portoghese (Brasile)" @@ -7824,6 +8344,14 @@ msgstr "Pos X:" msgid "Pos Y:" msgstr "Pos Y:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "Modello pubblico" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "I modelli pubblici sono collegati al tuo profilo pubblico. Ogni modifica ai modelli pubblici apparirà anche nel tuo profilo pubblico." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Azioni rapide" @@ -7980,6 +8558,11 @@ msgstr "Registra nuovamente" msgid "Re-register Email Domain" msgstr "Registra nuovamente il dominio email" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "Solo lettura" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Leggi la nostra documentazione per iniziare con NexaSign." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "Lettura del documento in corso" msgid "Ready" msgstr "Pronto" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "Attività recenti" msgid "Recent documents" msgstr "Documenti recenti" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "Accesso limitato" msgid "Retention of Documents" msgstr "Conservazione dei documenti" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Ritentato" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "Torna alla home" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Torna alla pagina di accesso a NexaSign qui" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "Registrati con Microsoft" msgid "Sign Up with OIDC" msgstr "Iscriviti con OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "Salta" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "Elenco di domini separato da spazi. Lascia vuoto per consentire tutti i msgid "Spanish" msgstr "Spagnolo" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Statistiche" @@ -9592,6 +10224,7 @@ msgstr "Statistiche" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "Chiave di accesso creata con successo" msgid "Successfully created: {successCount}" msgstr "Creati con successo: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Sommario:" @@ -9790,6 +10431,18 @@ msgstr "Sincronizzazione fallita, modifiche non salvate" msgid "Sync license from server" msgstr "Sincronizza la licenza dal server" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "Organizzazione di destinazione" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Squadra" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "Il team \"{0}\" è stato eliminato su NexaSign" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "Amministratore del team" msgid "Team Assignments" msgstr "Compiti del team" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "Email del team rimosso" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "Email del team rimosso per {teamName} su NexaSign" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "Modello caricato" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "Modelli eliminati parzialmente" msgid "Test" msgstr "Test" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Webhook di Test" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "Grazie per aver completato il processo di firma." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Grazie per aver utilizzato NexaSign per eseguire la firma elettronica dei tuoi documenti. Lo scopo di questa divulgazione è informarti sul processo, la legalità e i tuoi diritti riguardanti l'uso delle firme elettroniche sulla nostra piattaforma. Optando per l'utilizzo di una firma elettronica, accetti i termini e le condizioni delineati di seguito." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "I tipi di firma che i destinatari possono utilizzare quando firmano il d #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "L'URL per NexaSign per inviare eventi webhook." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "Questo documento è stato firmato da tutti i destinatari" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "Questo documento è disponibile nel tuo account NexaSign. Puoi visualizzare più dettagli, destinatari e log di controllo lì." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "Questo documento è stato creato utilizzando un link diretto." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "Titolo" msgid "Title cannot be empty" msgstr "Il titolo non può essere vuoto" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "Per accettare questo invito devi creare un account." @@ -11347,6 +12013,10 @@ msgstr "Rimuovi" msgid "Unsealed Documents" msgstr "Documenti non sigillati" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "Validazione fallita" msgid "Value" msgstr "Valore" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Codice di verifica richiesto" @@ -11782,6 +12483,10 @@ msgstr "Verticale" msgid "Vertical Align" msgstr "Allineamento verticale" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "Visualizzazione in corso" msgid "Visibility" msgstr "Visibilità" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "In attesa" @@ -11986,8 +12712,8 @@ msgstr "In attesa del tuo turno" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "Vuoi inviare link per la firma eleganti come questo? <0>Dai un'occhiata a NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "Vuoi il tuo profilo pubblico?" msgid "Warning: Assistant as last signer" msgstr "Avvertenza: Assistente come ultimo firmatario" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "Benvenuto a {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "Benvenuto su NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "Se abilitare il portale SSO per la tua organizzazione" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "Mentre aspetti che lo facciano, puoi creare il tuo account NexaSign e iniziare a firmare documenti subito." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "Chi vuoi ricordare?" msgid "Width:" msgstr "Larghezza:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Ritiro del consenso" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "Puoi rilevare i campi solo nelle buste in bozza" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "Puoi revocare l'accesso in qualsiasi momento dalle impostazioni del team su NexaSign <0>qui." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "Sei stato invitato da <0>{0} a unirti alla loro organizzazione." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "Sei stato invitato a unirti a {0} su NexaSign" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "La tua email" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "La tua email è già stata confermata. Ora puoi utilizzare tutte le funzionalità di NexaSign." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "La tua email è stata confermata con successo! Ora puoi utilizzare tutte le funzionalità di NexaSign." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Il tuo piano non supporta l'invito ai membri. Per favore, aggiorna il tuo piano o contatta le vendite <0>{SUPPORT_EMAIL} se desideri discutere le tue opzioni." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Il tuo piano non è più valido. Per favore, abbonati a un nuovo piano per continuare a utilizzare NexaSign." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "Il tuo codice di verifica:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "tuo-dominio.com altro-dominio.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/ja/web.po b/packages/lib/translations/ja/web.po index 42d69d4..6acba75 100644 --- a/packages/lib/translations/ja/web.po +++ b/packages/lib/translations/ja/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, other {選択したテンプレートを削除しようと msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "{0} フィールド" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} からドキュメント「{1}」への{recipientActionVerb}依頼が届いています。" +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0} が「{1}」を代表してドキュメント「{2}」の{recipientA msgid "{0} Teams" msgstr "{0} のチーム" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo}({os})" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, other {{charactersRemaining} 文字残り}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, other {このコードは # 分後に有効期限が切れます。}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference} が {documentName} に署名しました" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, other {# 文字残り}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount} 件選択済み" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} があなたに代わってアカウントを作成するようリクエストしています。" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} が、あなたの現在の NexaSign アカウントを自分たちの組織にリンクするようリクエストしています。" +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail} さんが、\"{0}\" を代表してこの文書の閲覧を招待しています。" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} が、NexaSign のチーム用メールアドレスとしてあなたのメールアドレスの使用をリクエストしました。" +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>全員 - すべてのユーザーがこの文書にアクセス msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>アカウント全体へのアクセス: プロフィール情報、設定、アクティビティのすべてを表示" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>認証方法を継承 - 「一般設定」ステップで設定されたグローバルなアクション署名認証方法を使用します" @@ -790,6 +821,10 @@ msgstr "無料の組織枠は残り 1 件です" msgid "1 month" msgstr "1 か月" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 か月" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "記録用に文書を印刷またはダウンロードする手段" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "メンバーが NexaSign の組織に参加しました" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "メンバーが組織 {organisationName} を離れました" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "メンバーが NexaSign の組織を離れました" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "あなたのためにアカウントを作成するリクエストが行われました" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "NexaSign アカウントをリンクするリクエストが行われました" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "NexaSign で {0} によって、あなたのメールアドレスを使用するリクエストが開始されました" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "NexaSign から送信されたリクエストであることを検証できるよう、お客様の URL に送信されるシークレットです。" +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "有効なメールアドレスを入力してください" msgid "A verification email will be sent to the provided email." msgstr "入力されたメールアドレス宛てに確認メールが送信されます。" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "アカウントを承認してリンク" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "NexaSign の組織参加招待を承諾" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "NexaSign 上の {teamName} のチームメールリクエストを承認" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "AI 機能" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "チームではAI機能が無効になっています。チームオーナーまたは組織オーナーに有効化を依頼してください。" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "すべてのテンプレート" msgid "All Time" msgstr "全期間" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "すべての組織メンバーがこのチームにアクセスできるようにします" @@ -1576,6 +1666,14 @@ msgstr "ほぼ完了しました" msgid "Already have an account? <0>Sign in instead" msgstr "すでにアカウントをお持ちですか?<0>サインイン" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "金額" @@ -1889,6 +1987,19 @@ msgstr "ページレイアウトを分析しています" msgid "Analyzing pages" msgstr "ページを分析しています" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "あなた宛てに招待されたドキュメントがここに表示されます" @@ -1913,6 +2024,10 @@ msgstr "API トークン" msgid "App Version" msgstr "アプリのバージョン" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "承認中" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "ドキュメントを完了してもよろしいですか?この操作は元に戻せません。すべての関連フィールドの事前入力が完了していることを確認してから続行してください。" @@ -2116,6 +2244,10 @@ msgstr "監査ログの詳細" msgid "Audit Logs" msgstr "監査ログ" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "バックアップコード" msgid "Banner Updated" msgstr "バナーを更新しました" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "開始する前に、下のボタンをクリックしてメールアドレスを確認してください。" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "請求" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "黒" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "2FA を有効にすると、メールとパスワードでサインインするたびに、認証アプリのコード入力が必要になります。" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "NexaSign が提供する電子署名サービスを利用することで、本開示文書を読み理解したことを表明したものとみなされます。また、ここに記載された電子署名および電子取引に関するすべての条件に同意したものとみなされます。" +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "ドキュメントを作成中" msgid "Creating Template" msgstr "テンプレートを作成中" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "CSV 構造" @@ -3338,6 +3535,10 @@ msgstr "カスタム組織グループ" msgid "Dark Mode" msgstr "ダークモード" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "日付形式" msgid "Date Settings" msgstr "日付設定" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David は従業員で、Lucas はマネージャーです" @@ -3625,11 +3834,20 @@ msgstr "削除済み" msgid "Deleting account..." msgstr "アカウントを削除しています..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "送信先" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "デバイス" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "パスワード変更をリクエストしていませんか?アカウントの安全確保をお手伝いしますので、<0>こちらからお問い合わせください。" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "ドキュメント" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "すべての受信者が署名したものの、まだ封印されてい msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "手書き" msgid "Draw signature" msgstr "手書き署名" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "PDFファイルをここにドロップするか、クリックして選択してください" @@ -4433,10 +4690,22 @@ msgstr "テンプレートを複製" msgid "Duplicate values are not allowed" msgstr "同じ値を重複して使用することはできません" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "オランダ語" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "例: 法務" msgid "eg. Mac" msgstr "例: Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "文書の電子的な配信" @@ -4800,6 +5077,10 @@ msgstr "同封文書" msgid "Enclosed Documents" msgstr "同封された文書" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "英語" @@ -4906,6 +5187,10 @@ msgstr "ここにテキストを入力してください" msgid "Enterprise" msgstr "Enterprise" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "封筒を送信しました" @@ -4952,6 +5237,14 @@ msgstr "封筒タイトル" msgid "Envelope updated" msgstr "封筒を更新しました" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "ページの読み込み中にエラーが発生しました。" msgid "Error uploading file" msgstr "ファイルのアップロード中にエラーが発生しました" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "有効期限: 残り {0}" msgid "Expires on {0}" msgstr "有効期限 {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "外部 ID" msgid "Extracting contact details" msgstr "連絡先情報を抽出しています" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "機能フラグ" msgid "Features" msgstr "機能" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "フィールドの文字数制限" @@ -5337,6 +5650,10 @@ msgstr "新しいサブスクリプションクレームを作成するための msgid "Filter by status" msgstr "ステータスで絞り込む" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "フランス語" msgid "Full Name" msgstr "氏名" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "リンクを生成" msgid "German" msgstr "ドイツ語" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "グローバル受信者アクション認証" @@ -5556,6 +5890,22 @@ msgstr "チームへ移動" msgid "Go to your <0>public profile settings to add documents." msgstr "<0>公開プロフィール設定に移動して文書を追加してください。" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "緑" @@ -5686,6 +6036,14 @@ msgstr "非表示" msgid "Hide license key" msgstr "ライセンスキーを非表示にする" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "横" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "この文書が送信されてから、受信者が完了するまでの猶予期間です。「継承」に設定すると、チームのデフォルト値が使用されます。" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "この組織と自分のアカウントをリンクすることに同意します" @@ -5790,10 +6152,41 @@ msgstr "受信トレイに確認リンクが見当たらない場合は、下か msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "認証アプリが QR コードに対応していない場合は、代わりに次のコードを使用できます。" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "重要: これが意味すること" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "含まれる内容:" msgid "Information" msgstr "情報" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "認証方法を継承" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "無効なライセンスキー" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "無効なライスタイプです。ご利用中の NexaSign インスタンスでは、ライセンスに含まれていない機能が使用されています。" +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "日本語" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "{organisationName} に NexaSign で参加" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "参加日" msgid "Joined {0}" msgstr "{0} に参加" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "このチームの主要な識別子と関連付けです。" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "韓国語" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "韓国語" msgid "Label" msgstr "ラベル" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "文字間隔" msgid "Letter Spacing" msgstr "文字間隔" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "ライトモード" msgid "Like to have your own public profile with agreements?" msgstr "自分の合意書付き公開プロフィールが欲しいですか?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "行の高さ" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "テンプレートをリンク" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "NexaSign アカウントをリンクする" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "フォームフィールドを探しています" msgid "Looking for signature fields" msgstr "署名フィールドを探しています" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "マネージャー" msgid "Managers and above" msgstr "マネージャー以上" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "フィールドを受信者に対応付けています" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "最小" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "ライセンスがありません。ご利用中の NexaSign インスタンスでは、ライセンスが必要な機能が使用されています。" +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "マイフォルダ" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "署名が必要" msgid "Needs to view" msgstr "閲覧が必要" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "なし" @@ -6791,13 +7267,21 @@ msgstr "新しいオプション {0}" msgid "New Password" msgstr "新しいパスワード" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "NexaSign ライセンス" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign は<0>すべての文書と、完了済み文書・署名・アカウントに紐づくその他すべてのリソースを削除します。" +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "値が見つかりません。" msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "大丈夫です。メールアドレスを入力していただければ、パスワードをリセットするための特別なリンクをメールでお送りします。" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "許可されるチーム数。0 = 無制限" msgid "Number Settings" msgstr "数値の設定" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "オフ" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "オン" @@ -7545,6 +8049,10 @@ msgstr "保留中の組織招待" msgid "Pending since" msgstr "保留開始日時" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "個人アカウント" msgid "Personal Inbox" msgstr "個人用受信箱" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "ロゴをアップロードしてください" msgid "Polish" msgstr "ポーランド語" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "ポルトガル語(ブラジル)" @@ -7824,6 +8344,14 @@ msgstr "X 位置:" msgid "Pos Y:" msgstr "Y 位置:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "公開テンプレート" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "公開テンプレートは公開プロフィールに紐づきます。公開テンプレートを変更すると、公開プロフィールにも反映されます。" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "クイックアクション" @@ -7980,6 +8558,11 @@ msgstr "再登録" msgid "Re-register Email Domain" msgstr "メールドメインを再登録" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "読み取り専用" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "NexaSign のドキュメントを読んで使い始めましょう。" +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "ドキュメントを読み込んでいます" msgid "Ready" msgstr "準備完了" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "最近のアクティビティ" msgid "Recent documents" msgstr "最近の文書" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "アクセス制限" msgid "Retention of Documents" msgstr "文書の保管" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "再試行済み" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "ホームに戻る" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "NexaSign のサインインページへ戻る" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "Microsoftでサインアップ" msgid "Sign Up with OIDC" msgstr "OIDC でサインアップ" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "スキップ" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "ドメインを半角スペース区切りで入力します。空のま msgid "Spanish" msgstr "スペイン語" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "統計" @@ -9592,6 +10224,7 @@ msgstr "統計" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "パスキーを作成しました" msgid "Successfully created: {successCount}" msgstr "正常に作成: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "概要:" @@ -9790,6 +10431,18 @@ msgstr "同期に失敗し、変更は保存されませんでした" msgid "Sync license from server" msgstr "サーバーからライセンスを同期" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "対象の組織" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "チーム" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "NexaSign にてチーム「{0}」が削除されました" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "チーム管理者" msgid "Team Assignments" msgstr "チーム割り当て" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "チームメールが削除されました" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "NexaSign にて {teamName} のチームメールが削除されました" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "テンプレートをアップロードしました" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "一部のテンプレートを削除しました" msgid "Test" msgstr "テスト" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "テスト Webhook" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "署名プロセスを完了していただきありがとうございます。" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "電子文書署名のために NexaSign をご利用いただきありがとうございます。本開示文書は、当社プラットフォーム上での電子署名のプロセス、法的有効性、およびお客様の権利について説明することを目的としています。電子署名を選択することで、以下に示す条件に同意したものとみなされます。" +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "受信者がドキュメントに署名する際に使用できる署名 #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "NexaSign が Webhook イベントを送信する先の URL です。" +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "この文書はすべての受信者によって署名されています" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "このドキュメントは NexaSign アカウントで利用できます。詳細、受信者、監査ログはそちらで確認できます。" +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "この文書はダイレクトリンクから作成されました。" #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "タイトル" msgid "Title cannot be empty" msgstr "タイトルを空にすることはできません" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "この招待を受け入れるにはアカウントを作成する必要があります。" @@ -11347,6 +12013,10 @@ msgstr "ピン留めを解除" msgid "Unsealed Documents" msgstr "未封印の文書" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "バリデーションに失敗しました" msgid "Value" msgstr "値" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "認証コードが必要です" @@ -11782,6 +12483,10 @@ msgstr "縦" msgid "Vertical Align" msgstr "縦位置揃え" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "閲覧中" msgid "Visibility" msgstr "公開範囲" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "保留中" @@ -11986,8 +12712,8 @@ msgstr "あなたの順番待ち" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "このようなスマートな署名リンクを送りたいですか?<0>NexaSign をチェックしてみてください。" +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "自分専用の公開プロフィールが欲しいですか?" msgid "Warning: Assistant as last signer" msgstr "警告: 最後の署名者がアシスタントです" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "{organisationName} へようこそ" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "NexaSign へようこそ!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "組織でSSOポータルを有効にするかどうか" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "相手からの対応を待つ間に、自分の NexaSign アカウントを作成して、すぐに文書署名を始めることができます。" +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "誰にリマインドを送りますか?" msgid "Width:" msgstr "幅:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "同意の撤回" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "ドラフトの封筒でのみフィールドを検出できます" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "NexaSign のチーム設定から、いつでもアクセス権を取り消すことができます。<0>こちら。" +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "<0>{0} から組織への参加を招待されています。" #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "NexaSign で {0} に参加するよう招待されています" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "あなたのメールアドレス" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "メールアドレスはすでに確認済みです。NexaSign のすべての機能をご利用いただけます。" +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "メールアドレスは正常に確認されました。NexaSign のすべての機能を利用できるようになりました。" +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "現在のプランではメンバーの招待はサポートされていません。プランのアップグレード、またはご相談をご希望の場合は <0>{SUPPORT_EMAIL} まで営業担当へお問い合わせください。" #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "現在のプランは無効です。NexaSign を引き続き利用するには、新しいプランを契約してください。" +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "認証コード:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/ko/web.po b/packages/lib/translations/ko/web.po index 7605135..5e9cffd 100644 --- a/packages/lib/translations/ko/web.po +++ b/packages/lib/translations/ko/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, other {선택한 템플릿을 삭제하려고 합니다.}}" msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "{0} 필드" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0}에서 \"{1}\" 문서에 대해 귀하께 {recipientActionVerb}하도록 초대했습니다." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0}이(가) \"{1}\"을(를) 대신하여 \"{2}\" 문서에 대해 귀하 msgid "{0} Teams" msgstr "{0} 팀" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} / {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, other {{charactersRemaining}자 남음}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, other {이 코드는 #분 후 만료됩니다.}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference}님이 {documentName}에 서명했습니다." msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, other {#자 남음}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount}개 선택함" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName}에서 귀하를 대신해 계정을 생성하려고 합니다." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName}에서 귀하의 기존 NexaSign 계정을 조직에 연결하려고 합니다." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail} 님이 \"{0}\"을(를) 대신하여 이 문서를 열람해 달라고 초대했습니다." #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} 팀에서 NexaSign에서 사용할 팀용 이메일 주소로 귀하의 이메일 주소를 요청했습니다." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>모든 사용자 - 모든 사용자가 이 문서에 접근하고 msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>전체 계정 접근: 프로필 정보, 설정 및 활동 전체 보기" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>인증 방식 상속 - \"일반 설정\" 단계에서 구성한 전역 액션 서명 인증 방식을 사용합니다." @@ -790,6 +821,10 @@ msgstr "무료 조직 1개 남음" msgid "1 month" msgstr "1개월" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12개월" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "기록용으로 문서를 인쇄하거나 다운로드할 수 있는 수단" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "구성원이 NexaSign의 조직에 가입했습니다." +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "구성원이 조직 {organisationName}을 떠났습니다." #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "구성원이 NexaSign의 조직을 떠났습니다." +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "귀하를 위한 계정 생성 요청이 있습니다." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "귀하의 NexaSign 계정을 연결해 달라는 요청이 있습니다." +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "NexaSign에서 {0}이(가) 귀하의 이메일 사용을 요청했습니다." +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "NexaSign에서 보낸 요청인지 확인할 수 있도록, 귀하의 URL로 전송되는 비밀 값입니다." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "유효한 이메일 주소를 입력해야 합니다" msgid "A verification email will be sent to the provided email." msgstr "입력한 이메일 주소로 확인 이메일이 전송됩니다." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "계정 수락 및 연결" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "NexaSign 조직 초대 수락" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "NexaSign에서 {teamName} 팀용 이메일 요청을 승인하세요." +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "AI 기능" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "AI 기능이 현재 팀에서 비활성화되어 있습니다. 팀 소유자 또는 조직 소유자에게 AI 기능을 활성화해 달라고 요청하세요." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "전체 템플릿" msgid "All Time" msgstr "전체 기간" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "모든 조직 구성원이 이 팀에 접근할 수 있도록 허용" @@ -1576,6 +1666,14 @@ msgstr "거의 완료되었습니다." msgid "Already have an account? <0>Sign in instead" msgstr "이미 계정이 있으신가요? <0>대신 로그인하기" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "금액" @@ -1889,6 +1987,19 @@ msgstr "페이지 레이아웃 분석 중" msgid "Analyzing pages" msgstr "페이지 분석 중" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "귀하를 초대한 문서는 여기에 표시됩니다." @@ -1913,6 +2024,10 @@ msgstr "API 토큰" msgid "App Version" msgstr "앱 버전" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "승인 중" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "문서를 완료하시겠습니까? 이 작업은 되돌릴 수 없습니다. 계속하기 전에 관련 필드를 모두 미리 채웠는지 확인해 주세요." @@ -2116,6 +2244,10 @@ msgstr "감사 로그 세부 정보" msgid "Audit Logs" msgstr "감사 로그" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "백업 코드" msgid "Banner Updated" msgstr "배너가 업데이트되었습니다" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "시작하기 전에 아래 버튼을 클릭하여 이메일 주소를 확인해 주세요." +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "결제" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "검정" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "2단계 인증을 활성화하면 이메일과 비밀번호로 로그인할 때마다 인증 앱에서 코드를 입력해야 합니다." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "NexaSign의 전자 서명 서비스를 계속 사용함으로써 귀하는 본 고지를 읽고 이해했음을 확인합니다. 또한 여기 명시된 전자 서명 및 전자 거래와 관련된 모든 약관에 동의합니다." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "문서 생성 중" msgid "Creating Template" msgstr "템플릿 생성 중" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "CSV 구조" @@ -3338,6 +3535,10 @@ msgstr "사용자 지정 조직 그룹" msgid "Dark Mode" msgstr "다크 모드" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "날짜 형식" msgid "Date Settings" msgstr "날짜 설정" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David는 직원이고, Lucas는 관리자입니다." @@ -3625,11 +3834,20 @@ msgstr "삭제됨" msgid "Deleting account..." msgstr "계정 삭제 중..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "대상" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "디바이스" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "비밀번호 변경을 요청하지 않으셨나요? 계정을 안전하게 보호하실 수 있도록 도와드리겠습니다. <0>문의하기만 해 주세요." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "문서" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "모든 수신자가 서명했지만 문서가 아직 봉인되지 않은 msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "그리기" msgid "Draw signature" msgstr "서명 그리기" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "여기에 PDF를 끌어다 놓거나 클릭하여 선택하세요" @@ -4433,10 +4690,22 @@ msgstr "템플릿 복제" msgid "Duplicate values are not allowed" msgstr "중복 값은 허용되지 않습니다" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "네덜란드어" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "예: Legal" msgid "eg. Mac" msgstr "예: Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "문서의 전자 제공" @@ -4800,6 +5077,10 @@ msgstr "동봉 문서" msgid "Enclosed Documents" msgstr "동봉된 문서들" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "영어" @@ -4906,6 +5187,10 @@ msgstr "여기에 텍스트를 입력하세요" msgid "Enterprise" msgstr "Enterprise" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "봉투가 배포되었습니다" @@ -4952,6 +5237,14 @@ msgstr "봉투 제목" msgid "Envelope updated" msgstr "봉투가 업데이트되었습니다" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "페이지를 불러오는 중 오류가 발생했습니다." msgid "Error uploading file" msgstr "파일 업로드 중 오류가 발생했습니다." +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "{0} 후 만료" msgid "Expires on {0}" msgstr "{0}에 만료됨" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "외부 ID" msgid "Extracting contact details" msgstr "연락처 정보 추출 중" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "기능 플래그" msgid "Features" msgstr "기능" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "필드 문자 수 제한" @@ -5337,6 +5650,10 @@ msgstr "새 구독 클레임을 생성하려면 세부 정보를 입력하세요 msgid "Filter by status" msgstr "상태로 필터링" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "프랑스어" msgid "Full Name" msgstr "전체 이름" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "링크 생성" msgid "German" msgstr "독일어" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "전역 수신자 액션 인증" @@ -5556,6 +5890,22 @@ msgstr "팀으로 이동" msgid "Go to your <0>public profile settings to add documents." msgstr "문서를 추가하려면 <0>공개 프로필 설정으로 이동하세요." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "녹색" @@ -5686,6 +6036,14 @@ msgstr "숨기기" msgid "Hide license key" msgstr "라이선스 키 숨기기" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "가로" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "이 문서가 전송된 후 수신자가 이를 완료할 수 있는 기간입니다. 상속으로 설정된 경우 팀 기본값을 사용합니다." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "이 조직과 계정을 연결하는 데 동의합니다" @@ -5790,10 +6152,41 @@ msgstr "받은편지함에서 확인 링크를 찾을 수 없다면 아래에서 msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "인증 앱이 QR 코드를 지원하지 않는 경우, 대신 다음 코드를 사용할 수 있습니다:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "중요: 이것이 의미하는 것" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "포함 사항:" msgid "Information" msgstr "정보" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "인증 방식 상속" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "잘못된 라이선스 키" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "잘못된 라이선스 유형 - 현재 NexaSign 인스턴스에서 사용 중인 기능은 보유한 라이선스에 포함되지 않습니다." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "일본어" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "NexaSign에서 {organisationName} 조직에 참여하세요." +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "가입일" msgid "Joined {0}" msgstr "{0}에 가입함" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "이 팀에 대한 주요 식별자와 관계입니다." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "한국어" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "한국어" msgid "Label" msgstr "레이블" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "자간" msgid "Letter Spacing" msgstr "자간" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "라이트 모드" msgid "Like to have your own public profile with agreements?" msgstr "계약이 포함된 나만의 공개 프로필을 원하시나요?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "줄 간격" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "템플릿 연결" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "NexaSign 계정 연결" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "양식 필드를 찾는 중" msgid "Looking for signature fields" msgstr "서명 필드를 찾는 중" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "관리자" msgid "Managers and above" msgstr "관리자 이상" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "필드를 수신자에 매핑하는 중" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "최소" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "라이선스 누락 - 현재 NexaSign 인스턴스에서 사용하는 기능에는 라이선스가 필요합니다." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "내 폴더" msgid "N/A" msgstr "해당 없음" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "서명 필요" msgid "Needs to view" msgstr "열람 필요" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "없음" @@ -6791,13 +7267,21 @@ msgstr "새 옵션 {0}" msgid "New Password" msgstr "새 비밀번호" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "NexaSign 라이선스" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign는 <0>모든 문서와 완료된 문서, 서명, 계정에 속한 모든 리소스를 삭제합니다." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "값이 없습니다." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "걱정하지 마세요. 이메일을 입력하시면 비밀번호를 재설정할 수 있는 특별 링크를 보내드립니다." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "허용되는 팀 수. 0 = 무제한" msgid "Number Settings" msgstr "숫자 설정" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "꺼짐" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "켜짐" @@ -7545,6 +8049,10 @@ msgstr "보류 중인 조직 초대" msgid "Pending since" msgstr "다음 시점부터 보류 중" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "개인 계정" msgid "Personal Inbox" msgstr "개인 받은편지함" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "로고를 업로드해 주세요." msgid "Polish" msgstr "폴란드어" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "포르투갈어(브라질)" @@ -7824,6 +8344,14 @@ msgstr "X 위치:" msgid "Pos Y:" msgstr "Y 위치:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "공개 템플릿" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "공개 템플릿은 공개 프로필과 연결됩니다. 공개 템플릿을 수정하면 공개 프로필에도 반영됩니다." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "빠른 작업" @@ -7980,6 +8558,11 @@ msgstr "재등록" msgid "Re-register Email Domain" msgstr "이메일 도메인 재등록" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "읽기 전용" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "문서를 읽고 NexaSign 사용을 시작하세요." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "문서를 읽는 중" msgid "Ready" msgstr "준비됨" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "최근 활동" msgid "Recent documents" msgstr "최근 문서" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "제한된 액세스" msgid "Retention of Documents" msgstr "문서 보존" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "재시도 횟수" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "홈으로 돌아가기" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "여기를 눌러 NexaSign 로그인 페이지로 돌아가기" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "Microsoft로 가입" msgid "Sign Up with OIDC" msgstr "OIDC로 가입" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "건너뛰기" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "도메인을 공백으로 구분하여 입력하세요. 비워 두면 msgid "Spanish" msgstr "스페인어" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "통계" @@ -9592,6 +10224,7 @@ msgstr "통계" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "패스키가 성공적으로 생성되었습니다" msgid "Successfully created: {successCount}" msgstr "성공적으로 생성됨: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "요약:" @@ -9790,6 +10431,18 @@ msgstr "동기화에 실패하여 변경 사항이 저장되지 않았습니다" msgid "Sync license from server" msgstr "서버에서 라이선스 동기화" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "대상 조직" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "팀" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "NexaSign에서 팀 \"{0}\"이(가) 삭제되었습니다." +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "팀 관리자" msgid "Team Assignments" msgstr "팀 할당" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "팀 이메일 제거됨" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "NexaSign에서 {teamName} 팀의 팀 이메일이 제거되었습니다" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "템플릿이 업로드되었습니다." #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "템플릿이 일부만 삭제되었습니다" msgid "Test" msgstr "테스트" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "테스트 웹후크" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "서명 프로세스를 완료해 주셔서 감사합니다." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "NexaSign를 통해 전자 문서 서명을 이용해 주셔서 감사합니다. 본 고지의 목적은 플랫폼에서 전자 서명을 사용할 때의 절차, 법적 효력 및 귀하의 권리를 안내하는 것입니다. 전자 서명을 선택함으로써 아래에 명시된 약관에 동의하는 것입니다." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "수신자가 문서에 서명할 때 사용할 수 있는 서명 유형 #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "NexaSign가 웹훅 이벤트를 전송할 URL입니다." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "이 문서는 모든 수신자가 서명했습니다" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "이 문서는 귀하의 NexaSign 계정에서 확인할 수 있습니다. 자세한 정보, 수신자, 감사 로그를 조회할 수 있습니다." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "이 문서는 직접 링크를 사용해 생성되었습니다." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "제목" msgid "Title cannot be empty" msgstr "제목은 비워 둘 수 없습니다." +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "이 초대를 수락하려면 계정을 생성해야 합니다." @@ -11347,6 +12013,10 @@ msgstr "고정 해제" msgid "Unsealed Documents" msgstr "봉인되지 않은 문서" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "검증 실패" msgid "Value" msgstr "값" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "인증 코드 필요" @@ -11782,6 +12483,10 @@ msgstr "세로" msgid "Vertical Align" msgstr "세로 정렬" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "열람 중" msgid "Visibility" msgstr "공개 범위" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "대기 중" @@ -11986,8 +12712,8 @@ msgstr "내 차례를 기다리는 중" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "이와 같이 세련된 서명 링크를 보내고 싶으신가요? <0>NexaSign를 확인해 보세요." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "나만의 공개 프로필을 원하시나요?" msgid "Warning: Assistant as last signer" msgstr "경고: 마지막 서명자로 지정된 보조자" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "{organisationName}에 오신 것을 환영합니다" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "NexaSign에 오신 것을 환영합니다!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "조직에 대해 SSO 포털을 활성화할지 여부" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "상대방을 기다리는 동안, NexaSign 계정을 생성하고 바로 전자 서명을 시작할 수 있습니다." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "누구에게 리마인더를 보내시겠습니까?" msgid "Width:" msgstr "너비:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "동의 철회" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "필드는 초안 봉투에서만 감지할 수 있습니다." #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "언제든지 NexaSign의 팀 설정에서 <0>여기에서 액세스를 취소할 수 있습니다." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "<0>{0} 조직에서 귀하를 초대했습니다." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "NexaSign에서 {0} 조직에 초대되었습니다." +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "이메일" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "이메일이 이미 확인되었습니다. 이제 NexaSign의 모든 기능을 사용할 수 있습니다." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "이메일이 성공적으로 확인되었습니다! 이제 NexaSign의 모든 기능을 사용할 수 있습니다." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "현재 요금제에서는 구성원 초대를 지원하지 않습니다. 요금제를 업그레이드하시거나, 옵션에 대해 논의하려면 <0>{SUPPORT_EMAIL}로 영업팀에 문의해 주세요." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "현재 요금제가 더 이상 유효하지 않습니다. NexaSign를 계속 사용하려면 새 요금제를 구독해 주세요." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "인증 코드:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/nl/web.po b/packages/lib/translations/nl/web.po index 358d7f4..c16e8a4 100644 --- a/packages/lib/translations/nl/web.po +++ b/packages/lib/translations/nl/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, one {U staat op het punt de geselecteerde sjabloon te verwij msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "{0}-veld" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} heeft je uitgenodigd om het document \"{1}\" te {recipientActionVerb}." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0} heeft namens \"{1}\" je uitgenodigd om het document \"{2}\" te {reci msgid "{0} Teams" msgstr "{0} teams" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} op {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {1 teken resterend} other {{charactersRemaining} tekens resterend}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {Deze code verloopt over # minuut.} other {Deze code verloopt over # minuten.}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference} heeft {documentName} ondertekend" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {# teken resterend} other {# tekens resterend}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "{selectedCount} geselecteerd" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} heeft verzocht om een account voor je aan te maken." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} heeft verzocht om je huidige NexaSign-account aan hun organisatie te koppelen." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail} namens \"{0}\" heeft je uitgenodigd om dit document te bekijken" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} heeft verzocht om je e-mailadres te gebruiken voor hun team op NexaSign." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>Iedereen - Iedereen kan toegang krijgen tot en het document bekij msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Volledige accounttoegang: Bekijk al je profielinformatie, instellingen en activiteit" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Authenticatiemethode overnemen - Gebruik de globale authenticatiemethode voor actie-ondertekening die is geconfigureerd in de stap \"Algemene instellingen\"" @@ -790,6 +821,10 @@ msgstr "1 gratis organisatie over" msgid "1 month" msgstr "1 maand" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 maanden" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "Een manier om documenten voor je administratie te printen of te downloaden" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "Een lid is toegetreden tot je organisatie op NexaSign" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "Een lid heeft je organisatie {organisationName} verlaten" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "Een lid heeft je organisatie op NexaSign verlaten" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "Er is een verzoek ingediend om een account voor je aan te maken" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "Er is een verzoek ingediend om je NexaSign-account te koppelen" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "Er is een verzoek ingediend door {0} op NexaSign om je e-mailadres te gebruiken." +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "Een geheim dat naar je URL wordt verzonden, zodat je kunt verifiëren dat het verzoek door NexaSign is verzonden." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "Een geldig e-mailadres is vereist" msgid "A verification email will be sent to the provided email." msgstr "Er wordt een verificatie-e-mail naar het opgegeven e-mailadres verzonden." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "Accepteren & account koppelen" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Uitnodiging accepteren om toe te treden tot een organisatie op NexaSign" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Team-e-mailverzoek voor {teamName} op NexaSign accepteren" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "AI-functies" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "AI-functies zijn uitgeschakeld voor je team. Vraag de eigenaar van je team of de eigenaar van de organisatie om ze in te schakelen." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "Alle sjablonen" msgid "All Time" msgstr "Alle tijd" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Alle organisatieleden toestaan toegang te hebben tot dit team" @@ -1576,6 +1666,14 @@ msgstr "Bijna klaar" msgid "Already have an account? <0>Sign in instead" msgstr "Heb je al een account? <0>Log dan in" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Bedrag" @@ -1889,6 +1987,19 @@ msgstr "Paginalay-out analyseren" msgid "Analyzing pages" msgstr "Pagina's analyseren" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Documenten waarvoor je aandacht nodig is, verschijnen hier" @@ -1913,6 +2024,10 @@ msgstr "API‑tokens" msgid "App Version" msgstr "App‑versie" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "Aan het goedkeuren" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "Weet je zeker dat je het document wilt voltooien? Deze actie kan niet ongedaan worden gemaakt. Zorg ervoor dat je alle relevante velden volledig vooraf hebt ingevuld voordat je doorgaat." @@ -2116,6 +2244,10 @@ msgstr "Details van auditlogboek" msgid "Audit Logs" msgstr "Auditlogs" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "Back‑upcodes" msgid "Banner Updated" msgstr "Banner bijgewerkt" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Bevestig je e-mailadres door op de onderstaande knop te klikken voordat je begint:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "Facturatie" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Zwart" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "Door 2FA in te schakelen, moet je elke keer dat je inlogt met e-mail en wachtwoord een code uit je authenticator-app invoeren." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "Door gebruik te maken van de elektronische ondertekeningsdienst van NexaSign bevestig je dat je deze kennisgeving hebt gelezen en begrepen. Je gaat akkoord met alle voorwaarden die hier zijn uiteengezet met betrekking tot het gebruik van elektronische handtekeningen en elektronische transacties." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "Document wordt gemaakt" msgid "Creating Template" msgstr "Sjabloon wordt gemaakt" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "CSV-structuur" @@ -3338,6 +3535,10 @@ msgstr "Aangepaste organisatiegroepen" msgid "Dark Mode" msgstr "Donker modus" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "Datumnotatie" msgid "Date Settings" msgstr "Datuminstellingen" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David is de werknemer, Lucas is de manager" @@ -3625,11 +3834,20 @@ msgstr "Verwijderd" msgid "Deleting account..." msgstr "Account wordt verwijderd..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Bestemming" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "Apparaat" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "Geen wachtwoordwijziging aangevraagd? We helpen je graag je account te beveiligen, neem gewoon <0>contact met ons op." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "Documentatie" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "Documenten waarvoor alle ontvangers hebben getekend, maar die nog niet z msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "Tekenen" msgid "Draw signature" msgstr "Handtekening tekenen" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "Zet de pdf hier neer of klik om te selecteren" @@ -4433,10 +4690,22 @@ msgstr "Sjabloon dupliceren" msgid "Duplicate values are not allowed" msgstr "Dubbele waarden zijn niet toegestaan" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "Nederlands" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "bijv. Legal" msgid "eg. Mac" msgstr "bijv. Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Elektronische levering van documenten" @@ -4800,6 +5077,10 @@ msgstr "Bijgevoegd document" msgid "Enclosed Documents" msgstr "Bijgevoegde documenten" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "Engels" @@ -4906,6 +5187,10 @@ msgstr "Voer hier je tekst in" msgid "Enterprise" msgstr "Enterprise" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Envelope gedistribueerd" @@ -4952,6 +5237,14 @@ msgstr "Enveloptitel" msgid "Envelope updated" msgstr "Envelope bijgewerkt" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "Fout bij het laden van de pagina" msgid "Error uploading file" msgstr "Fout bij uploaden van bestand" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "Verloopt over {0}" msgid "Expires on {0}" msgstr "Verloopt op {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "Externe ID" msgid "Extracting contact details" msgstr "Contactgegevens extraheren" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "Feature-flags" msgid "Features" msgstr "Functies" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Tekenlimiet veld" @@ -5337,6 +5650,10 @@ msgstr "Vul de gegevens in om een nieuwe abonnementsclaim aan te maken." msgid "Filter by status" msgstr "Filteren op status" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "Frans" msgid "Full Name" msgstr "Volledige naam" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "Links genereren" msgid "German" msgstr "Duits" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Globale ontvangeractie-authenticatie" @@ -5556,6 +5890,22 @@ msgstr "Ga naar team" msgid "Go to your <0>public profile settings to add documents." msgstr "Ga naar je <0>instellingen voor openbaar profiel om documenten toe te voegen." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Groen" @@ -5686,6 +6036,14 @@ msgstr "Verbergen" msgid "Hide license key" msgstr "Licentiesleutel verbergen" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "Horizontaal" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "Hoe lang ontvangers de tijd hebben om dit document te voltooien nadat het is verzonden. Gebruikt de standaardinstelling van het team wanneer overnemen is geselecteerd." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "Ik ga akkoord met het koppelen van mijn account aan deze organisatie" @@ -5790,10 +6152,41 @@ msgstr "Als je de bevestigingslink niet in je inbox vindt, kun je hieronder een msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "Als je authenticator‑app geen QR‑codes ondersteunt, kun je in plaats daarvan de volgende code gebruiken:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Belangrijk: wat dit betekent" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "Bevat:" msgid "Information" msgstr "Informatie" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Authenticatiemethode overnemen" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "Ongeldige licentiesleutel" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "Ongeldig licentietype - Je NexaSign-instantie gebruikt functies die niet onder je licentie vallen." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "Japans" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Word lid van {organisationName} op NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "Lid geworden" msgid "Joined {0}" msgstr "Toegetreden {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "Belangrijke identificatoren en relaties voor dit team." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "Koreaans" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "Koreaans" msgid "Label" msgstr "Label" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "Letterspatiëring" msgid "Letter Spacing" msgstr "Letterspatiëring" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "Lichte modus" msgid "Like to have your own public profile with agreements?" msgstr "Wil je een eigen openbaar profiel met overeenkomsten?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Regelhoogte" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "Sjabloon koppelen" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Koppel uw NexaSign-account" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "Zoeken naar formulier­velden" msgid "Looking for signature fields" msgstr "Zoeken naar handtekeningvelden" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "Manager" msgid "Managers and above" msgstr "Managers en hoger" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Velden aan ontvangers koppelen" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "Min" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "Licentie ontbreekt - Je NexaSign-instantie gebruikt functies waarvoor een licentie vereist is." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "Mijn map" msgid "N/A" msgstr "n.v.t." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "Moet ondertekenen" msgid "Needs to view" msgstr "Moet bekijken" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Nooit" @@ -6791,13 +7267,21 @@ msgstr "Nieuwe optie {0}" msgid "New Password" msgstr "Nieuw wachtwoord" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "NexaSign-licentie" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign verwijdert <0>al je documenten, samen met al je voltooide documenten, handtekeningen en alle andere bronnen die bij je account horen." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "Geen waarde gevonden." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "Geen zorgen, dat gebeurt wel eens! Vul je e‑mail in en we sturen je een speciale link om je wachtwoord te resetten." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "Aantal toegestane teams. 0 = onbeperkt" msgid "Number Settings" msgstr "Nummer-instellingen" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "Uit" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "Aan" @@ -7545,6 +8049,10 @@ msgstr "Openstaande organisatie-uitnodigingen" msgid "Pending since" msgstr "In behandeling sinds" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "Persoonlijk account" msgid "Personal Inbox" msgstr "Persoonlijke inbox" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "Upload een logo" msgid "Polish" msgstr "Pools" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "Portugees (Brazilië)" @@ -7824,6 +8344,14 @@ msgstr "Pos X:" msgid "Pos Y:" msgstr "Pos Y:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "Publieke sjabloon" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Openbare sjablonen zijn gekoppeld aan je openbare profiel. Alle wijzigingen aan openbare sjablonen worden ook zichtbaar in je openbare profiel." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Snelle acties" @@ -7980,6 +8558,11 @@ msgstr "Opnieuw registreren" msgid "Re-register Email Domain" msgstr "E-maildomein opnieuw registreren" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "Alleen-lezen" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Lees onze documentatie om aan de slag te gaan met NexaSign." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "Uw document wordt gelezen" msgid "Ready" msgstr "Klaar" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "Recente activiteit" msgid "Recent documents" msgstr "Recente documenten" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "Beperkte toegang" msgid "Retention of Documents" msgstr "Bewaring van documenten" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Opnieuw geprobeerd" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "Terug naar home" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Ga hier terug naar de NexaSign-aanmeldpagina" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "Registreren met Microsoft" msgid "Sign Up with OIDC" msgstr "Registreren met OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "Overslaan" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "Door spaties gescheiden lijst met domeinen. Laat leeg om alle domeinen t msgid "Spanish" msgstr "Spaans" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Statistieken" @@ -9592,6 +10224,7 @@ msgstr "Statistieken" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "Passkey succesvol aangemaakt" msgid "Successfully created: {successCount}" msgstr "Succesvol aangemaakt: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Overzicht:" @@ -9790,6 +10431,18 @@ msgstr "Synchroniseren mislukt, wijzigingen niet opgeslagen" msgid "Sync license from server" msgstr "Licentie met server synchroniseren" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "Doelorganisatie" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Team" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "Team \"{0}\" is verwijderd op NexaSign" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "Teambeheerder" msgid "Team Assignments" msgstr "Teamtoewijzingen" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "Teame-mailadres verwijderd" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "Teame-mailadres verwijderd voor {teamName} op NexaSign" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "Sjabloon geüpload" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "Templates gedeeltelijk verwijderd" msgid "Test" msgstr "Test" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Webhook testen" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "Bedankt dat je het ondertekeningsproces hebt voltooid." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Bedankt dat je NexaSign gebruikt om je documenten elektronisch te ondertekenen. Het doel van deze kennisgeving is je te informeren over het proces, de rechtsgeldigheid en je rechten met betrekking tot het gebruik van elektronische handtekeningen op ons platform. Door te kiezen voor een elektronische handtekening ga je akkoord met de onderstaande voorwaarden." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "De typen handtekeningen die ontvangers mogen gebruiken bij het onderteke #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "De URL waarnaar NexaSign webhook‑gebeurtenissen stuurt." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "Dit document is door alle ontvangers ondertekend" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "Dit document is beschikbaar in je NexaSign-account. Je kunt daar meer details, ontvangers en auditlogs bekijken." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "Dit document is aangemaakt met een directe link." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "Titel" msgid "Title cannot be empty" msgstr "Titel mag niet leeg zijn" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "Om deze uitnodiging te accepteren, moet je een account aanmaken." @@ -11347,6 +12013,10 @@ msgstr "Losmaken" msgid "Unsealed Documents" msgstr "Onverzegelde documenten" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "Validatie mislukt" msgid "Value" msgstr "Waarde" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Verificatiecode vereist" @@ -11782,6 +12483,10 @@ msgstr "Verticaal" msgid "Vertical Align" msgstr "Verticaal uitlijnen" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "Bekijken" msgid "Visibility" msgstr "Zichtbaarheid" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "Wachten" @@ -11986,8 +12712,8 @@ msgstr "Wachten op jouw beurt" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "Wil je ook van die strakke ondertekenlinks versturen zoals deze? <0>Bekijk NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "Wil je een eigen openbaar profiel?" msgid "Warning: Assistant as last signer" msgstr "Waarschuwing: Assistent als laatste ondertekenaar" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "Welkom bij {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "Welkom bij NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "Of het SSO-portaal voor uw organisatie moet worden ingeschakeld" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "Terwijl je daarop wacht, kun je je eigen NexaSign‑account aanmaken en direct beginnen met documenten ondertekenen." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "Wie wil je herinneren?" msgid "Width:" msgstr "Breedte:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Toestemming intrekken" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "U kunt alleen velden detecteren in concept-enveloppen" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "Je kunt de toegang op elk moment intrekken in je teaminstellingen op NexaSign, <0>hier." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "Je bent door <0>{0} uitgenodigd om lid te worden van hun organisatie #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "Je bent uitgenodigd om {0} op NexaSign te joinen" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "Uw e-mailadres" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "Je e-mailadres is al bevestigd. Je kunt nu alle functies van NexaSign gebruiken." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "Je e‑mail is succesvol bevestigd! Je kunt nu alle functies van NexaSign gebruiken." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Je abonnement ondersteunt geen uitnodigingen van leden. Upgrade je abonnement of neem contact op met sales via <0>{SUPPORT_EMAIL} om je opties te bespreken." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Je abonnement is niet langer geldig. Neem een nieuw abonnement om NexaSign te blijven gebruiken." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "Uw verificatiecode:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/pl/web.po b/packages/lib/translations/pl/web.po index 1f8b206..53c8ffd 100644 --- a/packages/lib/translations/pl/web.po +++ b/packages/lib/translations/pl/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, one {Zamierzasz usunąć zaznaczony szablon.} few {Zamierzas msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "{0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "Sprawdź i {recipientActionVerb} dokument „{1}” utworzony przez zespół {0}." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "Sprawdź i {recipientActionVerb} dokument „{2}” utworzony przez uż msgid "{0} Teams" msgstr "Zespół {0}" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} na {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {Pozostał # znak} few {Pozostały {charactersRemaining} znaki} many {Pozostało {charactersRemaining} znaków} other {Pozostało {charactersRemaining} znaków}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {Kod wygaśnie za # minutę.} few {Kod wygaśnie za # minuty.} many {Kod wygaśnie za # minut.} other {Kod wygaśnie za # minuty.}}" @@ -434,6 +457,10 @@ msgstr "Użytkownik {recipientReference} podpisał dokument „{documentName}” msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {Pozostał # znak} few {Pozostały # znaki} many {Pozostało # znaków} other {Pozostało # znaków}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "Zaznaczono {selectedCount}" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "Organizacja <0>{organisationName} poprosiła o utworzenie konta w Twoim imieniu." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "Organizacja <0>{organisationName} poprosiła o połączenie Twojego konta NexaSign z ich organizacją." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "Użytkownik <0>{senderName} {senderEmail} z zespołu „{0}” zaprosił Cię do wyświetlenia dokumentu" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "Zespół <0>{teamName} poprosił o możliwość używania Twojego adresu e-mail w zespole NexaSign." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>Wszyscy – Każdy może uzyskać dostęp do dokumentu i go wyśw msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Pełny dostęp do konta: Wyświetlanie informacji o profilu, ustawieniach i aktywności" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Odziedzicz metodę uwierzytelniania – Użyj metody uwierzytelniania skonfigurowanej w domyślnych ustawieniach" @@ -790,6 +821,10 @@ msgstr "Pozostała 1 darmowa organizacja" msgid "1 month" msgstr "1 miesiąc" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 miesięcy" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "Środka do drukowania lub pobierania dokumentów w formie elektronicznej" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "Użytkownik dołączył do organizacji w NexaSign" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "Użytkownik opuścił organizację {organisationName}" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "Użytkownik opuścił organizację w NexaSign" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "Utworzono prośbę o utworzenie konta dla Ciebie" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "Utworzono prośbę o połączenie Twojego konta NexaSign" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "Prośba użycia Twojego adresu e-mail została wysłana przez zespół {0} w NexaSign" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "Sekret, który zostanie wysłany na Twój adres URL, abyś mógł zweryfikować, że prośba została wysłana przez NexaSign." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "Adres e-mail jest nieprawidłowy" msgid "A verification email will be sent to the provided email." msgstr "Wiadomość weryfikacyjna zostanie wysłana na podany adres e-mail." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "Zaakceptuj i połącz konto" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Zaakceptuj zaproszenie do organizacji w NexaSign" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Zaakceptuj adres e-mail zespołu {teamName} w NexaSign" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "Funkcje AI" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "Funkcje AI są wyłączone w zespole. Poproś właściciela zespołu lub organizacji o ich włączenie." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "Wszystkie szablony" msgid "All Time" msgstr "Cały czas" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Zezwalaj wszystkim użytkownikom organizacji na dostęp do tego zespołu" @@ -1576,6 +1666,14 @@ msgstr "Prawie gotowe" msgid "Already have an account? <0>Sign in instead" msgstr "Masz już konto? <0>Zaloguj się" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Kwota" @@ -1889,6 +1987,19 @@ msgstr "Analizowanie układu strony" msgid "Analyzing pages" msgstr "Analizowanie stron" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Wszystkie zaproszenia do dokumentów pojawią się tutaj" @@ -1913,6 +2024,10 @@ msgstr "Tokeny API" msgid "App Version" msgstr "Wersja aplikacji" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "Zatwierdza" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "Czy na pewno chcesz zakończyć dokument? Ta akcja jest nieodwracalna. Upewnij się, że wypełniono wszystkie pola." @@ -2116,6 +2244,10 @@ msgstr "Szczegóły dziennika logu" msgid "Audit Logs" msgstr "Dziennik logów" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "Kody zapasowe" msgid "Banner Updated" msgstr "Baner został zaktualizowany" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Zanim zaczniesz, potwierdź adres e-mail, klikając poniższy przycisk:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "Płatności" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Czarny" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "Po włączeniu weryfikacji dwuetapowej konieczne będzie wpisanie kodu z aplikacji uwierzytelniającej przy każdym logowaniu za pomocą hasła." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "Korzystając z usługi podpisu elektronicznego świadczonej przez NexaSign, potwierdzasz zapoznanie się z niniejszą informacją. Wyrażasz zgodę na wszystkie warunki związane z korzystaniem z podpisów elektronicznych i transakcji elektronicznych opisanych w niniejszym dokumencie." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "Tworzenie dokumentu" msgid "Creating Template" msgstr "Tworzenie szablonu" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "Struktura CSV" @@ -3338,6 +3535,10 @@ msgstr "Niestandardowe grupy w organizacji" msgid "Dark Mode" msgstr "Tryb ciemny" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "Format daty" msgid "Date Settings" msgstr "Ustawienia daty" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David jest pracownikiem. Lucas jest managerem." @@ -3625,11 +3834,20 @@ msgstr "Usunięto" msgid "Deleting account..." msgstr "Usuwanie konta..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Adres docelowy" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "Urządzenie" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "To nie Twoja prośba? Jesteśmy tutaj, aby pomóc Ci zabezpieczyć konto. <0>Skontaktuj się z nami." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "Dokumentacja" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "Dokumenty, które zostały podpisane przez wszystkich odbiorców, ale ni msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "Rysowany" msgid "Draw signature" msgstr "Podpis rysowany" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "Upuść plik PDF tutaj lub kliknij, aby wybrać" @@ -4433,10 +4690,22 @@ msgstr "Duplikuj szablon" msgid "Duplicate values are not allowed" msgstr "Zduplikowane wartości nie są dozwolone" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "Holenderski" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "np. Dział prawny" msgid "eg. Mac" msgstr "np. Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Elektroniczne dostarczanie dokumentów" @@ -4800,6 +5077,10 @@ msgstr "Załączony dokument" msgid "Enclosed Documents" msgstr "Załączniki" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "Angielski" @@ -4906,6 +5187,10 @@ msgstr "Wpisz tekst" msgid "Enterprise" msgstr "Enterprise" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Wysłano kopertę" @@ -4952,6 +5237,14 @@ msgstr "Tytuł koperty" msgid "Envelope updated" msgstr "Koperta została zaktualizowana" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "Wystąpił błąd podczas ładowania strony" msgid "Error uploading file" msgstr "Wystąpił błąd podczas przesyłania pliku" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "Wygaśnie za {0}" msgid "Expires on {0}" msgstr "Wygasa {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "Identyfikator zewnętrzny" msgid "Extracting contact details" msgstr "Wyodrębnianie danych kontaktowych" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "Flagi funkcji" msgid "Features" msgstr "Funkcje" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Limit znaków" @@ -5337,6 +5650,10 @@ msgstr "Uzupełnił szczegóły, aby utworzyć nową subskrypcję." msgid "Filter by status" msgstr "Filtruj według statusu" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "Francuski" msgid "Full Name" msgstr "Imię i nazwisko" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "Wygeneruj linki" msgid "German" msgstr "Niemiecki" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Domyślne metody uwierzytelniania odbiorcy" @@ -5556,6 +5890,22 @@ msgstr "Przejdź do zespołu" msgid "Go to your <0>public profile settings to add documents." msgstr "Przejdź do <0>ustawień profilu publicznego, aby dodać dokumenty." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Zielony" @@ -5686,6 +6036,14 @@ msgstr "Ukryj" msgid "Hide license key" msgstr "Ukryj klucz licencyjny" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "Poziomo" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "Czas, w którym odbiorcy muszą zakończyć dokument. Opcja dziedziczenia korzysta z domyślnych ustawień zespołu." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "Zgadzam się połączyć moje konto z organizacją" @@ -5790,10 +6152,41 @@ msgstr "Jeśli nie znajdziesz wiadomości z linkiem potwierdzającym, możesz po msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "Jeśli Twoja aplikacja uwierzytelniająca nie obsługuje kodów QR, użyj poniższego kodu:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Uwaga: Co to oznacza" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "Zawiera:" msgid "Information" msgstr "Informacje" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Odziedzicz metodę uwierzytelniania" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "Klucz licencyjny jest nieprawidłowy" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "Nieprawidłowy rodzaj licencji – Instancja NexaSign korzysta z funkcji, które nie są objęte Twoją licencją." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "Japoński" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Dołącz do organizacji {organisationName} w NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "Dołączył" msgid "Joined {0}" msgstr "Dołączył {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "Kluczowe identyfikatory i powiązania dla tego zespołu." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "Koreański" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "Koreański" msgid "Label" msgstr "Etykieta" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "Odstęp liter" msgid "Letter Spacing" msgstr "Odstęp liter" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "Tryb jasny" msgid "Like to have your own public profile with agreements?" msgstr "Czy chcesz mieć własny profil publiczny z umowami?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Wysokość linii" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "Połącz szablon" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Połącz swoje konto NexaSign" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "Wyszukiwanie pól formularza" msgid "Looking for signature fields" msgstr "Wyszukiwanie pól podpisu" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "Manager" msgid "Managers and above" msgstr "Managerowie i wyżej" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Mapowanie pól dla odbiorców" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "Min" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "Brak licencji – Twoja instancja NexaSign korzysta z funkcji, które wymagają licencji." +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "Mój folder" msgid "N/A" msgstr "Nie dotyczy" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "Musi podpisać" msgid "Needs to view" msgstr "Musi wyświetlić" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Nigdy" @@ -6791,13 +7267,21 @@ msgstr "Nowa opcja {0}" msgid "New Password" msgstr "Nowe hasło" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "Licencja NexaSign" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign usunie <0>wszystkie Twoje dokumenty (w tym zakończone), podpisy oraz dane powiązane z kontem." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "Nie znaleziono wartości." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "Nie martw się! Wpisz swój adres e-mail, a my wyślemy Ci specjalny link do zresetowania hasła." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "Liczba dozwolonych zespołów. 0 = Bez ograniczeń" msgid "Number Settings" msgstr "Ustawienia liczby" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "Wyłączone" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "Włączone" @@ -7545,6 +8049,10 @@ msgstr "Oczekujące zaproszenia do organizacji" msgid "Pending since" msgstr "Oczekuje od" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "Konto osobiste" msgid "Personal Inbox" msgstr "Skrzynka odbiorcza" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "Prześlij logo" msgid "Polish" msgstr "Polski" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "Portugalski (Brazylia)" @@ -7824,6 +8344,14 @@ msgstr "Pozycja X:" msgid "Pos Y:" msgstr "Pozycja Y:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "Szablon publiczny" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Szablony publiczne są powiązane z Twoim profilem publicznym. Wszelkie zmiany szablonów publicznych pojawią się również w Twoim profilu publicznym." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Szybkie akcje" @@ -7980,6 +8558,11 @@ msgstr "Zarejestruj ponownie" msgid "Re-register Email Domain" msgstr "Zarejestruj ponownie domenę" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "Tylko do odczytu" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Przeczytaj naszą dokumentację, aby rozpocząć korzystanie z NexaSign." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "Odczytywanie dokumentu" msgid "Ready" msgstr "Gotowy" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "Ostatnia aktywność" msgid "Recent documents" msgstr "Ostatnie dokumenty" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "Dostęp ograniczony" msgid "Retention of Documents" msgstr "Przechowywanie dokumentów" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Ponowiono" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "Powrót do strony głównej" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Powrót do strony logowania NexaSign" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "Zarejestruj się przez Microsoft" msgid "Sign Up with OIDC" msgstr "Zarejestruj się przez OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "Pomiń" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "Lista domen oddzielonych spacjami. Pozostaw puste pole, aby zezwolić na msgid "Spanish" msgstr "Hiszpański" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "Logowanie SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Statystyki" @@ -9592,6 +10224,7 @@ msgstr "Statystyki" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "Klucz dostępu został utworzony" msgid "Successfully created: {successCount}" msgstr "Pomyślnie utworzono: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Podsumowanie:" @@ -9790,6 +10431,18 @@ msgstr "Synchronizacja nie powiodła się. Zmiany nie zostały zapisane" msgid "Sync license from server" msgstr "Synchronizuj licencję z serwera" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "Docelowa organizacja" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Zespół" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "Zespół „{0}” został usunięty z NexaSign" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "Administrator zespołu" msgid "Team Assignments" msgstr "Przypisane zespoły" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "Adres e-mail zespołu został usunięty" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "Adres e-mail zespołu {teamName} został usunięty" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "Szablon został przesłany" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "Szablony zostały częściowo usunięte" msgid "Test" msgstr "Testuj" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Testuj webhook" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "Podpisywanie zostało zakończone." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Dziękujemy za korzystanie z NexaSign do podpisywania dokumentów elektronicznych. Celem niniejszego oświadczenia jest poinformowanie Cię o procesie, legalności i Twoich prawach dotyczących korzystania z podpisów elektronicznych na naszej platformie. Decydując się na korzystanie z podpisu elektronicznego, wyrażasz zgodę na warunki określone poniżej." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "Rodzaje podpisów, których odbiorcy mogą używać podczas podpisywania #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "Adres URL dla NexaSign do wysyłania zdarzeń webhook." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "Dokument został podpisany przez wszystkich odbiorców" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "Na Twoim koncie w NexaSign dostępny jest dokument. Możesz zobaczyć więcej szczegółów, odbiorców i dziennik logów." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "Dokument został utworzony za pomocą bezpośredniego linku." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10906,6 +11568,10 @@ msgstr "Tytuł" msgid "Title cannot be empty" msgstr "Tytuł nie może być pusty" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "Aby zaakceptować zaproszenie, musisz utworzyć konto." @@ -11349,6 +12015,10 @@ msgstr "Odepnij" msgid "Unsealed Documents" msgstr "Niezapieczętowane dokumenty" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11729,6 +12399,37 @@ msgstr "Walidacja nie powiodła się" msgid "Value" msgstr "Wartość" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Kod weryfikacyjny jest wymagany" @@ -11784,6 +12485,10 @@ msgstr "Pionowo" msgid "Vertical Align" msgstr "Wyrównanie w pionie" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11965,6 +12670,27 @@ msgstr "Wyświetla" msgid "Visibility" msgstr "Widoczność" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "Oczekiwanie" @@ -11988,8 +12714,8 @@ msgstr "Oczekiwanie na Ciebie" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "Chcesz wysyłać eleganckie linki do podpisywania, takie jak ten? <0>Sprawdź NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12007,6 +12733,22 @@ msgstr "Chcesz mieć profil publiczny?" msgid "Warning: Assistant as last signer" msgstr "Ostrzeżenie: Asystent jako ostatni podpisujący" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12417,8 +13159,8 @@ msgid "Welcome to {organisationName}" msgstr "Witaj w organizacji {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "Witaj w NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12456,8 +13198,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "Czy chcesz włączyć logowanie SSO dla Twojej organizacji?" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "W międzyczasie możesz utworzyć swoje konto NexaSign i od razu rozpocząć podpisywanie dokumentów." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12472,6 +13214,10 @@ msgstr "Kogo chcesz przypomnieć?" msgid "Width:" msgstr "Szerokość:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Wycofanie zgody" @@ -12712,8 +13458,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "Możesz wykrywać pola tylko w kopertach w wersji roboczej" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "W każdej chwili możesz unieważnić dostęp w <0>ustawieniach zespołu w NexaSign." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12857,8 +13603,8 @@ msgstr "Organizacja <0>{0} zaprasza Cię do dołączenia do nich." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "Dołącz do organizacji {0} w NexaSign" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13408,12 +14154,12 @@ msgid "Your Email" msgstr "Twój adres e-mail" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "Adres e-mail został już potwierdzony. Możesz korzystać ze wszystkich funkcji NexaSign." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "Adres e-mail został pomyślnie potwierdzony! Możesz korzystać ze wszystkich funkcji NexaSign." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13481,8 +14227,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Twój plan nie obsługuje zapraszania użytkowników. Zaktualizuj plan lub skontaktuj się z działem sprzedaży pod adresem <0>{SUPPORT_EMAIL}, jeśli chcesz omówić swoje opcje." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Twój plan nie jest prawidłowy. Wybierz nowy plan, aby korzystać z NexaSign." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13582,3 +14328,19 @@ msgstr "Twój kod weryfikacyjny:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/pt-BR/web.po b/packages/lib/translations/pt-BR/web.po index 9f5f7bc..a2a1135 100644 --- a/packages/lib/translations/pt-BR/web.po +++ b/packages/lib/translations/pt-BR/web.po @@ -247,6 +247,11 @@ msgstr "" msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -263,6 +268,14 @@ msgstr "" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} convidou você para {recipientActionVerb} o documento \"{1}\"." +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -288,6 +301,12 @@ msgstr "{0} em nome de \"{1}\" convidou você para {recipientActionVerb} o docum msgid "{0} Teams" msgstr "{0} Equipes" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -323,6 +342,10 @@ msgstr "{browserInfo} em {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, one {1 caractere restante} other {{charactersRemaining} caracteres restantes}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, one {Este código expirará em # minuto.} other {Este código expirará em # minutos.}}" @@ -429,6 +452,10 @@ msgstr "{recipientReference} assinou {documentName}" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, one {# caractere restante} other {# caracteres restantes}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "" @@ -625,8 +652,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} solicitou a criação de uma conta em seu nome." #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} solicitou vincular sua conta atual do NexaSign à organização deles." +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -665,8 +692,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail} em nome de \"{0}\" convidou você para visualizar este documento" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} solicitou o uso do seu endereço de e-mail para a equipe deles no NexaSign." +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -701,6 +728,10 @@ msgstr "<0>Todos - Todos podem acessar e visualizar o documento" msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>Acesso total à conta: Visualize todas as informações do seu perfil, configurações e atividades" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>Herdar método de autenticação - Use o método de autenticação de assinatura de ação global configurado na etapa \"Configurações Gerais\"" @@ -785,6 +816,10 @@ msgstr "1 organização gratuita restante" msgid "1 month" msgstr "1 mês" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 meses" @@ -924,8 +959,8 @@ msgid "A means to print or download documents for your records" msgstr "Um meio de imprimir ou baixar documentos para seus registros" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "Um membro entrou na sua organização no NexaSign" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -936,8 +971,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "Um membro deixou sua organização {organisationName}" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "Um membro deixou sua organização no NexaSign" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -976,18 +1011,18 @@ msgid "A request has been made to create an account for you" msgstr "Uma solicitação foi feita para criar uma conta para você" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "Uma solicitação foi feita para vincular sua conta NexaSign" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "Uma solicitação para usar seu e-mail foi iniciada por {0} no NexaSign" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "Um segredo que será enviado para sua URL para que você possa verificar se a solicitação foi enviada pelo NexaSign." +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1023,6 +1058,18 @@ msgstr "" msgid "A verification email will be sent to the provided email." msgstr "Um e-mail de verificação será enviado para o e-mail fornecido." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1034,12 +1081,12 @@ msgid "Accept & Link Account" msgstr "Aceitar e Vincular Conta" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "Aceitar convite para entrar em uma organização no NexaSign" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "Aceitar solicitação de e-mail da equipe para {teamName} no NexaSign" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1456,6 +1503,37 @@ msgstr "Recursos de IA" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1528,6 +1606,18 @@ msgstr "Todos os modelos" msgid "All Time" msgstr "Todo o Período" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "Permitir que todos os membros da organização acessem esta equipe" @@ -1571,6 +1661,14 @@ msgstr "Quase pronto" msgid "Already have an account? <0>Sign in instead" msgstr "Já tem uma conta? <0>Faça login" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "Valor" @@ -1884,6 +1982,19 @@ msgstr "Analisando o layout da página" msgid "Analyzing pages" msgstr "Analisando páginas" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "Quaisquer documentos para os quais você foi convidado aparecerão aqui" @@ -1908,6 +2019,10 @@ msgstr "Tokens de API" msgid "App Version" msgstr "Versão do App" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1957,6 +2072,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "Aprovando" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "Tem certeza de que deseja concluir o documento? Esta ação não pode ser desfeita. Certifique-se de ter preenchido todos os campos relevantes antes de prosseguir." @@ -2111,6 +2239,10 @@ msgstr "" msgid "Audit Logs" msgstr "Logs de Auditoria" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2179,14 +2311,67 @@ msgstr "Códigos de backup" msgid "Banner Updated" msgstr "Banner Atualizado" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "Antes de começar, confirme seu endereço de e-mail clicando no botão abaixo:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2197,6 +2382,14 @@ msgstr "" msgid "Billing" msgstr "Faturamento" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "Preto" @@ -2308,8 +2501,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "Ao ativar a 2FA, você precisará inserir um código do seu aplicativo autenticador toda vez que fizer login usando senha de e-mail." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "Ao prosseguir com o uso do serviço de assinatura eletrônica fornecido pela NexaSign, você afirma que leu e compreendeu esta divulgação. Você concorda com todos os termos e condições relacionados ao uso de assinaturas eletrônicas e transações eletrônicas conforme descrito aqui." +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3276,6 +3469,10 @@ msgstr "" msgid "Creating Template" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "Estrutura CSV" @@ -3333,6 +3530,10 @@ msgstr "Grupos de Organização Personalizados" msgid "Dark Mode" msgstr "Modo Escuro" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3368,6 +3569,14 @@ msgstr "Formato de Data" msgid "Date Settings" msgstr "Configurações de Data" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David é o Funcionário, Lucas é o Gerente" @@ -3620,11 +3829,20 @@ msgstr "Excluído" msgid "Deleting account..." msgstr "Excluindo conta..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "Destino" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3691,6 +3909,22 @@ msgstr "Dispositivo" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4192,8 +4426,6 @@ msgid "Documentation" msgstr "Documentação" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4255,6 +4487,27 @@ msgstr "" msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4366,6 +4619,10 @@ msgstr "Desenhar" msgid "Draw signature" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "" @@ -4428,10 +4685,22 @@ msgstr "Duplicar Modelo" msgid "Duplicate values are not allowed" msgstr "Valores duplicados não são permitidos" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4476,6 +4745,14 @@ msgstr "ex: Jurídico" msgid "eg. Mac" msgstr "ex: Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "Entrega Eletrônica de Documentos" @@ -4795,6 +5072,10 @@ msgstr "Documento Anexo" msgid "Enclosed Documents" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "" @@ -4901,6 +5182,10 @@ msgstr "Digite seu texto aqui" msgid "Enterprise" msgstr "Empresarial" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "Envelope distribuído" @@ -4947,6 +5232,14 @@ msgstr "Título do Envelope" msgid "Envelope updated" msgstr "Envelope atualizado" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5043,6 +5336,14 @@ msgstr "" msgid "Error uploading file" msgstr "Erro ao carregar arquivo" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5111,6 +5412,10 @@ msgstr "Expira em {0}" msgid "Expires on {0}" msgstr "Expira em {0}" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5121,6 +5426,10 @@ msgstr "ID Externo" msgid "Extracting contact details" msgstr "Extraindo detalhes de contato" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5252,6 +5561,10 @@ msgstr "Sinalizadores de Recurso" msgid "Features" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "Limite de caracteres do campo" @@ -5332,6 +5645,10 @@ msgstr "Preencha os detalhes para criar uma nova reivindicação de assinatura." msgid "Filter by status" msgstr "" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5444,6 +5761,10 @@ msgstr "" msgid "Full Name" msgstr "Nome Completo" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5468,6 +5789,19 @@ msgstr "Gerar Links" msgid "German" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "Autenticação de ação de destinatário global" @@ -5551,6 +5885,22 @@ msgstr "Ir para a equipe" msgid "Go to your <0>public profile settings to add documents." msgstr "Vá para suas <0>configurações de perfil público para adicionar documentos." +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "Verde" @@ -5681,6 +6031,14 @@ msgstr "Ocultar" msgid "Hide license key" msgstr "" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5705,6 +6063,10 @@ msgstr "Horizontal" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "Concordo em vincular minha conta a esta organização" @@ -5785,10 +6147,41 @@ msgstr "Se você não encontrar o link de confirmação em sua caixa de entrada, msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "Se seu aplicativo autenticador não suportar códigos QR, você pode usar o seguinte código:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "Importante: O que isso significa" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5842,6 +6235,10 @@ msgstr "" msgid "Information" msgstr "Informação" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "Herdar método de autenticação" @@ -5932,7 +6329,7 @@ msgid "Invalid License Key" msgstr "" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx @@ -6063,8 +6460,8 @@ msgid "Japanese" msgstr "" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "Junte-se a {organisationName} no NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6077,14 +6474,38 @@ msgstr "Entrou" msgid "Joined {0}" msgstr "Entrou {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6097,6 +6518,10 @@ msgstr "" msgid "Label" msgstr "Rótulo" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6208,6 +6633,23 @@ msgstr "Espaçamento entre letras" msgid "Letter Spacing" msgstr "Espaçamento entre Letras" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6237,6 +6679,11 @@ msgstr "Modo Claro" msgid "Like to have your own public profile with agreements?" msgstr "Gostaria de ter seu próprio perfil público com contratos?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "Altura da linha" @@ -6259,8 +6706,8 @@ msgid "Link template" msgstr "" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "Vincule sua conta NexaSign" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6332,6 +6779,14 @@ msgstr "Procurando campos de formulário" msgid "Looking for signature fields" msgstr "Procurando campos de assinatura" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6501,6 +6956,15 @@ msgstr "Gerente" msgid "Managers and above" msgstr "Gerentes e acima" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "Mapeando campos para destinatários" @@ -6604,7 +7068,7 @@ msgid "Min" msgstr "Mín" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." +msgid "Missing License - Your NexaFile instance is using features that require a license." msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx @@ -6697,6 +7161,10 @@ msgstr "Minha Pasta" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6757,6 +7225,14 @@ msgstr "Precisa assinar" msgid "Needs to view" msgstr "Precisa visualizar" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "Nunca" @@ -6786,13 +7262,21 @@ msgstr "" msgid "New Password" msgstr "Nova Senha" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "A NexaSign excluirá <0>todos os seus documentos, juntamente com todos os seus documentos concluídos, assinaturas e todos os outros recursos pertencentes à sua conta." +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7000,6 +7484,18 @@ msgstr "Nenhum valor encontrado." msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "Não se preocupe, acontece! Digite seu e-mail e enviaremos um link especial para redefinir sua senha." +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7070,10 +7566,18 @@ msgstr "Número de equipes permitidas. 0 = Ilimitado" msgid "Number Settings" msgstr "Configurações de Número" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "" @@ -7540,6 +8044,10 @@ msgstr "" msgid "Pending since" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7568,6 +8076,10 @@ msgstr "Conta Pessoal" msgid "Personal Inbox" msgstr "Caixa de Entrada Pessoal" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7805,6 +8317,14 @@ msgstr "Por favor, faça upload de um logotipo" msgid "Polish" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "" @@ -7819,6 +8339,14 @@ msgstr "" msgid "Pos Y:" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7944,6 +8472,56 @@ msgstr "Modelo Público" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Modelos públicos estão conectados ao seu perfil público. Quaisquer modificações em modelos públicos também aparecerão no seu perfil público." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Ações Rápidas" @@ -7975,6 +8553,11 @@ msgstr "" msgid "Re-register Email Domain" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7989,8 +8572,8 @@ msgid "Read Only" msgstr "Somente Leitura" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "Leia nossa documentação para começar com o NexaSign." +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8009,6 +8592,14 @@ msgstr "Lendo seu documento" msgid "Ready" msgstr "Pronto" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8047,6 +8638,11 @@ msgstr "Atividade recente" msgid "Recent documents" msgstr "Documentos recentes" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8533,6 +9129,10 @@ msgstr "Acesso Restrito" msgid "Retention of Documents" msgstr "Retenção de Documentos" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "Tentado novamente" @@ -8564,8 +9164,8 @@ msgid "Return to Home" msgstr "Retornar para Início" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "Retornar para a página de login do NexaSign aqui" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9234,6 +9834,22 @@ msgstr "Inscrever-se com Microsoft" msgid "Sign Up with OIDC" msgstr "Inscrever-se com OIDC" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9417,7 +10033,11 @@ msgid "Skip" msgstr "Pular" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9568,10 +10188,22 @@ msgstr "Lista de domínios separados por espaço. Deixe em branco para permitir msgid "Spanish" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "Estatísticas" @@ -9587,6 +10219,7 @@ msgstr "Estatísticas" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9749,6 +10382,14 @@ msgstr "Passkey criada com sucesso" msgid "Successfully created: {successCount}" msgstr "Criado com sucesso: {successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "Resumo:" @@ -9785,6 +10426,18 @@ msgstr "Falha na sincronização, alterações não salvas" msgid "Sync license from server" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9809,14 +10462,15 @@ msgstr "" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "Equipe" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "A equipe \"{0}\" foi excluída no NexaSign" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9826,6 +10480,10 @@ msgstr "Administrador da Equipe" msgid "Team Assignments" msgstr "Atribuições da Equipe" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9867,8 +10525,8 @@ msgid "Team email removed" msgstr "E-mail da equipe removido" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "E-mail da equipe removido para {teamName} no NexaSign" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10082,7 +10740,6 @@ msgid "Template uploaded" msgstr "Modelo enviado" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10103,6 +10760,11 @@ msgstr "" msgid "Test" msgstr "Teste" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "Testar Webhook" @@ -10153,8 +10815,8 @@ msgid "Thank you for completing the signing process." msgstr "Obrigado por concluir o processo de assinatura." #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "Obrigado por usar o NexaSign para realizar sua assinatura eletrônica de documentos. O objetivo desta divulgação é informá-lo sobre o processo, legalidade e seus direitos em relação ao uso de assinaturas eletrônicas em nossa plataforma. Ao optar por usar uma assinatura eletrônica, você concorda com os termos e condições descritos abaixo." +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10517,8 +11179,8 @@ msgstr "Os tipos de assinaturas que os destinatários podem usar ao assinar o do #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "A URL para o NexaSign enviar eventos de webhook." +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10662,8 +11324,8 @@ msgid "This document has been signed by all recipients" msgstr "Este documento foi assinado por todos os destinatários" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "Este documento está disponível em sua conta NexaSign. Você pode ver mais detalhes, destinatários e logs de auditoria lá." +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10682,7 +11344,7 @@ msgid "This document was created using a direct link." msgstr "Este documento foi criado usando um link direto." #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10899,6 +11561,10 @@ msgstr "Título" msgid "Title cannot be empty" msgstr "O título não pode estar vazio" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "Para aceitar este convite, você deve criar uma conta." @@ -11342,6 +12008,10 @@ msgstr "Desafixar" msgid "Unsealed Documents" msgstr "" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11722,6 +12392,37 @@ msgstr "Falha na validação" msgid "Value" msgstr "Valor" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "Código de Verificação Necessário" @@ -11777,6 +12478,10 @@ msgstr "Vertical" msgid "Vertical Align" msgstr "Alinhamento Vertical" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11958,6 +12663,27 @@ msgstr "Visualizando" msgid "Visibility" msgstr "Visibilidade" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "Aguardando" @@ -11981,7 +12707,7 @@ msgstr "Aguardando Sua Vez" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx @@ -12000,6 +12726,22 @@ msgstr "Quer seu próprio perfil público?" msgid "Warning: Assistant as last signer" msgstr "Aviso: Assistente como último signatário" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12410,8 +13152,8 @@ msgid "Welcome to {organisationName}" msgstr "Bem-vindo à {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "Bem-vindo ao NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12449,8 +13191,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "Se deve ativar o portal SSO para sua organização" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "Enquanto espera que eles façam isso, você pode criar sua própria conta NexaSign e começar a assinar documentos imediatamente." +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12465,6 +13207,10 @@ msgstr "Quem você deseja lembrar?" msgid "Width:" msgstr "" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "Retirada de Consentimento" @@ -12705,7 +13451,7 @@ msgid "You can only detect fields in draft envelopes" msgstr "Você só pode detectar campos em envelopes de rascunho" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx @@ -12850,8 +13596,8 @@ msgstr "Você foi convidado por <0>{0} para participar da organização dele #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "Você foi convidado para participar de {0} no NexaSign" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13401,12 +14147,12 @@ msgid "Your Email" msgstr "Seu E-mail" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "Seu e-mail já foi confirmado. Agora você pode usar todos os recursos do NexaSign." +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "Seu e-mail foi confirmado com sucesso! Agora você pode usar todos os recursos do NexaSign." +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13474,8 +14220,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "Seu plano não suporta convidar membros. Por favor, atualize seu plano ou entre em contato com vendas em <0>{SUPPORT_EMAIL} se desejar discutir suas opções." #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "Seu plano não é mais válido. Por favor, assine um novo plano para continuar usando o NexaSign." +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13575,3 +14321,19 @@ msgstr "Seu código de verificação:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "seu-dominio.com outro-dominio.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/translations/zh/web.po b/packages/lib/translations/zh/web.po index b188463..955c670 100644 --- a/packages/lib/translations/zh/web.po +++ b/packages/lib/translations/zh/web.po @@ -252,6 +252,11 @@ msgstr "{0, plural, other {你即将删除 # 个模板。}}" msgid "{0}" msgstr "{0}" +#. placeholder {0}: result.attachmentsAdded +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "{0} Anhang/Anhänge wieder verfügbar." +msgstr "" + #. placeholder {0}: team.name #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "{0} direct signing templates" @@ -268,6 +273,14 @@ msgstr "{0} 字段" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} 已邀请您 {recipientActionVerb} 文档“{1}”。" +#. placeholder {0}: run.documentsAuto +#. placeholder {1}: run.documentsManual +#. placeholder {2}: run.documentsIgnored +#. placeholder {3}: run.mailsChecked +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "{0} importiert, {1} manuell, {2} ignoriert · {3} Mails geprüft" +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -293,6 +306,12 @@ msgstr "{0} 代表“{1}”邀请您 {recipientActionVerb} 文档“{2}”。" msgid "{0} Teams" msgstr "{0} 个团队" +#. placeholder {0}: data.documents.length +#. placeholder {1}: data.total +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{0} von {1} angezeigt" +msgstr "" + #. placeholder {0}: currentStepData.order #. placeholder {1}: envelopeEditorSteps.length #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx @@ -328,6 +347,10 @@ msgstr "{browserInfo} 于 {os}" msgid "{charactersRemaining, plural, one {1 character remaining} other {{charactersRemaining} characters remaining}}" msgstr "{charactersRemaining, plural, other {{charactersRemaining} 个字符剩余}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{downloadableCount} davon mit Anhang — ZIP enthält MANIFEST.txt mit Liste der übersprungenen Mails." +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "{expiresInMinutes, plural, one {This code will expire in # minute.} other {This code will expire in # minutes.}}" msgstr "{expiresInMinutes, plural, other {此代码将在 # 分钟后过期。}}" @@ -434,6 +457,10 @@ msgstr "{recipientReference} 已签署 {documentName}" msgid "{remaningLength, plural, one {# character remaining} other {# characters remaining}}" msgstr "{remaningLength, plural, other {# 个字符剩余}}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "{selectedCount} ausgewählt" +msgstr "" + #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "{selectedCount} selected" msgstr "已选择 {selectedCount} 个" @@ -630,8 +657,8 @@ msgid "<0>{organisationName} has requested to create an account on your beha msgstr "<0>{organisationName} 请求代表您创建一个账户。" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "<0>{organisationName} has requested to link your current NexaSign account to their organisation." -msgstr "<0>{organisationName} 请求将您当前的 NexaSign 账户关联到其组织。" +msgid "<0>{organisationName} has requested to link your current NexaFile account to their organisation." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -670,8 +697,8 @@ msgid "<0>{senderName} {senderEmail} on behalf of \"{0}\" has invited you to msgstr "<0>{senderName} {senderEmail} 代表 \"{0}\" 邀请你查看此文档" #: packages/email/templates/confirm-team-email.tsx -msgid "<0>{teamName} has requested to use your email address for their team on NexaSign." -msgstr "<0>{teamName} 请求将您的邮箱地址用于其在 NexaSign 上的团队。" +msgid "<0>{teamName} has requested to use your email address for their team on NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "<0>Account management: Modify your account settings, permissions, and preferences" @@ -706,6 +733,10 @@ msgstr "<0>所有人 - 所有人都可以访问并查看此文档" msgid "<0>Full account access: View all your profile information, settings, and activity" msgstr "<0>完整账户访问: 查看您的所有个人资料信息、设置和活动" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "<0>Für Z2 und Z3 liefert NexaFile das CLI-Tool <1>nexasign-gobd-export — siehe nächster Abschnitt." +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "<0>Inherit authentication method - Use the global action signing authentication method configured in the \"General Settings\" step" msgstr "<0>继承认证方式 - 使用在“常规设置”步骤中配置的全局操作签署认证方式" @@ -790,6 +821,10 @@ msgstr "剩余 1 个免费组织" msgid "1 month" msgstr "1 个月" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "11 pragmatische, rechtlich solide Vorlagen nach BGB / HGB / TzBfG / DSGVO. Jede Vorlage als geführter Generator: Felder ausfüllen, PDF erzeugen, in NexaFile hochladen und signieren. Die Markdown-Rohvorlagen bleiben zusätzlich auf den Generator-Seiten verlinkt." +msgstr "" + #: apps/remix/app/components/forms/token.tsx msgid "12 months" msgstr "12 个月" @@ -929,8 +964,8 @@ msgid "A means to print or download documents for your records" msgstr "用于打印或下载文档以作记录的方式" #: packages/email/templates/organisation-join.tsx -msgid "A member has joined your organisation on NexaSign" -msgstr "有成员已在 NexaSign 上加入您的组织" +msgid "A member has joined your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" @@ -941,8 +976,8 @@ msgid "A member has left your organisation {organisationName}" msgstr "有成员已离开您的组织 {organisationName}" #: packages/email/templates/organisation-leave.tsx -msgid "A member has left your organisation on NexaSign" -msgstr "有成员已在 NexaSign 上离开您的组织" +msgid "A member has left your organisation on NexaFile" +msgstr "" #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" @@ -981,18 +1016,18 @@ msgid "A request has been made to create an account for you" msgstr "已收到为您创建账户的请求" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "A request has been made to link your NexaSign account" -msgstr "已收到关联您的 NexaSign 账户的请求" +msgid "A request has been made to link your NexaFile account" +msgstr "" #. placeholder {0}: team.name #: packages/lib/server-only/team/create-team-email-verification.ts -msgid "A request to use your email has been initiated by {0} on NexaSign" -msgstr "{0} 在 NexaSign 上发起了一个使用您邮箱的请求" +msgid "A request to use your email has been initiated by {0} on NexaFile" +msgstr "" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaSign." -msgstr "一个密钥将被发送到你的 URL,以便你验证该请求确实由 NexaSign 发出。" +msgid "A secret that will be sent to your URL so you can verify that the request has been sent by NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "A stable internet connection" @@ -1028,6 +1063,18 @@ msgstr "需要提供有效的电子邮箱地址" msgid "A verification email will be sent to the provided email." msgstr "验证邮件将发送到所填写的邮箱。" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbrechen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Abbruch wird ausgeführt" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-invitations.tsx #: packages/email/templates/confirm-team-email.tsx #: packages/email/templates/organisation-invite.tsx @@ -1039,12 +1086,12 @@ msgid "Accept & Link Account" msgstr "接受并关联账户" #: packages/email/templates/organisation-invite.tsx -msgid "Accept invitation to join an organisation on NexaSign" -msgstr "接受加入 NexaSign 组织的邀请" +msgid "Accept invitation to join an organisation on NexaFile" +msgstr "" #: packages/email/templates/confirm-team-email.tsx -msgid "Accept team email request for {teamName} on NexaSign" -msgstr "在 NexaSign 上接受 {teamName} 的团队邮箱请求" +msgid "Accept team email request for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acceptance and Consent" @@ -1461,6 +1508,37 @@ msgstr "AI 功能" msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." msgstr "您团队的 AI 功能已被禁用。请联系您团队的所有者或组织所有者为其启用。" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Aktion" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion ausgeführt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Aktion fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Aktiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Akzeptiert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Akzeptiert · GoBD-gesperrt" +msgstr "" + #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "All" @@ -1533,6 +1611,18 @@ msgstr "所有模板" msgid "All Time" msgstr "全部时间" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Alle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Alle Belege" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Alle Quellen" +msgstr "" + #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" msgstr "允许所有组织成员访问此团队" @@ -1576,6 +1666,14 @@ msgstr "即将完成" msgid "Already have an account? <0>Sign in instead" msgstr "已经有账号?<0>改为登录" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Als Beleg akzeptieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Als manuell zu ziehen markieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-billing-invoices-table.tsx msgid "Amount" msgstr "金额" @@ -1889,6 +1987,19 @@ msgstr "正在分析页面布局" msgid "Analyzing pages" msgstr "正在分析页面" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Anbieter auswählen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Anhänge + Mail als ZIP" +msgstr "" + #: apps/remix/app/routes/_authenticated+/inbox.tsx msgid "Any documents that you have been invited to will appear here" msgstr "任何邀请您参与的文档都会显示在此处" @@ -1913,6 +2024,10 @@ msgstr "API 令牌" msgid "App Version" msgstr "应用版本" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "App-Passwort" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -1962,6 +2077,19 @@ msgctxt "Recipient role progressive verb" msgid "Approving" msgstr "审批中" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Archivieren" +msgstr "" + #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx msgid "Are you sure you want to complete the document? This action cannot be undone. Please ensure that you have completed prefilling all relevant fields before proceeding." msgstr "您确定要完成此文档吗?此操作无法撤销。请确保您已完成所有相关字段的预填后再继续。" @@ -2116,6 +2244,10 @@ msgstr "审计日志详情" msgid "Audit Logs" msgstr "审计日志" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Auswahl aufheben" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Authentication Level" @@ -2184,14 +2316,67 @@ msgstr "备份代码" msgid "Banner Updated" msgstr "横幅已更新" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Bausteine" +msgstr "" + +#. placeholder {0}: formatDateTime(run.finishedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Beendet {0}" +msgstr "" + #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" msgstr "在开始之前,请点击下方按钮确认您的邮箱地址:" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bei Gmail/Outlook: in den Konto-Einstellungen ein App-Passwort erzeugen statt das Login-Passwort zu nutzen." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Beispiel-Nutzer" msgstr "" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Beleg-Detail" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege aus allen verbundenen Quellen an einem Ort — durchsuchbar und nach Status gefiltert." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Belege aus Ihrem Postfach werden automatisch im Eingang einsortiert. Zugangsdaten werden verschlüsselt gespeichert und sind nur für Sie sichtbar." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Belege erscheinen hier, sobald Sie eine Quelle verbunden und einen Sync-Lauf gestartet haben." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Belege ziehen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bereits importierte Belege bleiben erhalten. Neue Belege werden ab sofort nicht mehr eingelesen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Betreff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Bezeichnung" +msgstr "" + #: apps/remix/app/components/general/settings-nav-desktop.tsx #: apps/remix/app/components/general/settings-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx @@ -2202,6 +2387,14 @@ msgstr "" msgid "Billing" msgstr "账单" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Bis" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Bis (exklusiv)" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Black" msgstr "黑色" @@ -2313,8 +2506,8 @@ msgid "By enabling 2FA, you will be required to enter a code from your authentic msgstr "启用 2FA 后,每次使用邮箱和密码登录时,您都需要输入来自验证器应用的验证码。" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "By proceeding to use the electronic signature service provided by NexaSign, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." -msgstr "继续使用 NexaSign 提供的电子签署服务,即表示你已阅读并理解本披露内容。你同意本文件中关于使用电子签名及电子交易的所有条款和条件。" +msgid "By proceeding to use the electronic signature service provided by NexaFile, you affirm that you have read and understood this disclosure. You agree to all terms and conditions related to the use of electronic signatures and electronic transactions as outlined herein." +msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-disclosure.tsx msgid "By proceeding with your electronic signature, you acknowledge and consent that it will be used to sign the given document and holds the same legal validity as a handwritten signature. By completing the electronic signing process, you affirm your understanding and acceptance of these conditions." @@ -3281,6 +3474,10 @@ msgstr "正在创建文档" msgid "Creating Template" msgstr "正在创建模板" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "CSV exportieren" +msgstr "" + #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" msgstr "CSV 结构" @@ -3338,6 +3535,10 @@ msgstr "自定义组织组" msgid "Dark Mode" msgstr "深色模式" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Das Von-Datum muss vor dem Bis-Datum liegen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/dashboard.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Dashboard" @@ -3373,6 +3574,14 @@ msgstr "日期格式" msgid "Date Settings" msgstr "日期设置" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Dateien im Archiv" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Datum" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "David is the Employee, Lucas is the Manager" msgstr "David 是员工,Lucas 是经理" @@ -3625,11 +3834,20 @@ msgstr "已删除" msgid "Deleting account..." msgstr "正在删除账号..." +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Der Fortschritt wird unten angezeigt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Der Lauf ist angelegt. Aktualisieren Sie die Liste in Kürze." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx msgid "Destination" msgstr "目标地址" #: apps/remix/app/components/general/webhook-logs-sheet.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Details" @@ -3696,6 +3914,22 @@ msgstr "设备" msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us." msgstr "如果你没有请求更改密码?我们可以帮助你保护账户安全,只需<0>联系我们。" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Die Verantwortungs-Teilung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle existiert nicht oder wurde gelöscht." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Diese Quelle ist gesperrt." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Diese Vorlagen dienen zur <0>Orientierung und stellen keine Rechtsberatung i.S.d. Rechtsdienstleistungsgesetzes dar. Vor produktiver Verwendung bitte durch zugelassene/n Rechtsanwältin/-anwalt prüfen lassen. Die Nutzung erfolgt auf eigenes Risiko." +msgstr "" + #: apps/remix/app/components/general/template/template-direct-link-badge.tsx #: apps/remix/app/components/tables/templates-table.tsx msgid "direct link" @@ -4197,8 +4431,6 @@ msgid "Documentation" msgstr "文档" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-desktop.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx #: apps/remix/app/components/general/skeletons/document-edit-skeleton.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx @@ -4260,6 +4492,27 @@ msgstr "所有收件人都已签署但文档尚未加盖签章的文档。卡住 msgid "Dokumente" msgstr "" +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente archivieren" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente erstellen" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Dokumente finden" +msgstr "" + +#: apps/remix/app/components/general/app-nav-desktop.tsx +#: apps/remix/app/components/general/app-nav-mobile.tsx +msgid "Dokumente signieren" +msgstr "" + #: apps/remix/app/components/tables/organisation-email-domains-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Domain" @@ -4371,6 +4624,10 @@ msgstr "绘制" msgid "Draw signature" msgstr "手写签名" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Drei aufeinanderfolgende Login-Fehler. Bitte Zugangsdaten prüfen und reaktivieren." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-item-edit-dialog.tsx msgid "Drop PDF here or click to select" msgstr "将 PDF 拖放到此处,或点击以选择" @@ -4433,10 +4690,22 @@ msgstr "复制模板" msgid "Duplicate values are not allowed" msgstr "不允许重复的值" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Durchsuchung konnte nicht gestartet werden" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Dutch" msgstr "荷兰语" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "E-Mail-Adresse" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx msgid "E.g. 0" @@ -4481,6 +4750,14 @@ msgstr "例如:Legal" msgid "eg. Mac" msgstr "例如:Mac" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Eigenen Host eingeben…" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Eingang" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Electronic Delivery of Documents" msgstr "文档的电子交付" @@ -4800,6 +5077,10 @@ msgstr "随附文档" msgid "Enclosed Documents" msgstr "随附文件" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Endgültig entfernen" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "English" msgstr "英语" @@ -4906,6 +5187,10 @@ msgstr "在此输入你的文本" msgid "Enterprise" msgstr "企业版" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Entfernen fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "Envelope distributed" msgstr "信封已分发" @@ -4952,6 +5237,14 @@ msgstr "信封标题" msgid "Envelope updated" msgstr "信封已更新" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erkannter Betrag" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Erneut aus IMAP laden" +msgstr "" + #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-delete-dialog.tsx #: apps/remix/app/components/dialogs/admin-user-disable-dialog.tsx @@ -5048,6 +5341,14 @@ msgstr "加载页面时出错" msgid "Error uploading file" msgstr "上传文件时出错" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Erster Sync läuft im Hintergrund." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Es läuft bereits ein Sync für diese Quelle. Bitte warten oder oben abbrechen." +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Event" @@ -5116,6 +5417,10 @@ msgstr "将在 {0} 后过期" msgid "Expires on {0}" msgstr "将于 {0} 到期" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Export-CLI — " +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/document-flow/add-settings.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx @@ -5126,6 +5431,10 @@ msgstr "外部 ID" msgid "Extracting contact details" msgstr "正在提取联系方式" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Fachbegriffe & FAQ" +msgstr "" + #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Failed" @@ -5257,6 +5566,10 @@ msgstr "功能开关" msgid "Features" msgstr "功能" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Fehler" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" msgstr "字段字符限制" @@ -5337,6 +5650,10 @@ msgstr "填写详细信息以创建新的订阅声明。" msgid "Filter by status" msgstr "按状态筛选" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Finanzamt-Zugriff: Z1, Z2, Z3" +msgstr "" + #: apps/remix/app/components/dialogs/document-move-to-folder-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx #: apps/remix/app/components/dialogs/template-move-to-folder-dialog.tsx @@ -5449,6 +5766,10 @@ msgstr "法语" msgid "Full Name" msgstr "全名" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Für signierte Dokumente startet die Aufbewahrung mit <0>completedAt. Für gefundene Belege startet sie mit <1>acceptedAt, also in dem Moment, in dem Sie den Beleg als relevant übernehmen. Der Retention-Check meldet Belege, die auf die 10-Jahres-Frist zulaufen oder sie überschritten haben; er löscht nichts automatisch." +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/direct-template/direct-template-page.tsx #: apps/remix/app/components/general/document/document-edit-form.tsx @@ -5473,6 +5794,19 @@ msgstr "生成链接" msgid "German" msgstr "德语" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Geschäftspostfach" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Gesperrt" +msgstr "" + +#. placeholder {0}: formatDateTime(run.startedAt, locale) +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Gestartet {0}" +msgstr "" + #: packages/ui/components/document/document-global-auth-action-select.tsx msgid "Global recipient action authentication" msgstr "全局收件人操作认证" @@ -5556,6 +5890,22 @@ msgstr "前往团队" msgid "Go to your <0>public profile settings to add documents." msgstr "前往你的<0>公开资料设置添加文档。" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD steht für <0>„Grundsätze zur ordnungsmäßigen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff\" — ein BMF-Schreiben aus dem Jahr 2019, das für alle deutschen Unternehmen verbindlich ist, die Bücher führen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Archivierung" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-konforme Archivierung mit NexaFile" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "GoBD-Konformität ist <0>nie die Leistung eines einzelnen Tools. Sie entsteht aus dem Zusammenspiel von drei Elementen:" +msgstr "" + #: packages/ui/primitives/signature-pad/signature-pad-color-picker.tsx msgid "Green" msgstr "绿色" @@ -5686,6 +6036,14 @@ msgstr "隐藏" msgid "Hide license key" msgstr "隐藏许可证密钥" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Hinweis: Der Export nimmt gefundene Belege auf, sobald sie akzeptiert wurden. Die Mail-Artefakte werden vom Host-Pfad <0>NEXASIGN_DISCOVERY_ARCHIVE_PATH gelesen; Standard ist <1>/var/lib/nexasign-archive." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Holt die Mail nochmal vom Mailserver und schreibt Anhänge + .eml ins Archiv." +msgstr "" + #: apps/remix/app/components/dialogs/folder-move-dialog.tsx #: apps/remix/app/components/general/folder/folder-grid.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -5710,6 +6068,10 @@ msgstr "水平" msgid "How long recipients have to complete this document after it is sent. Uses the team default when set to inherit." msgstr "设置此文档在发送后,收件人可完成签署的时间长度。当设置为继承时,将使用团队默认值。" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "HTML-Variante als Datei verfügbar — wird aus Sicherheitsgründen nicht inline angezeigt." +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "I agree to link my account with this organization" msgstr "我同意将我的账户与此组织关联" @@ -5790,10 +6152,41 @@ msgstr "如果在收件箱中未找到确认链接,你可以在下方重新请 msgid "If your authenticator app does not support QR codes, you can use the following code instead:" msgstr "如果你的验证器应用不支持二维码,你可以使用以下代码:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Ignorieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Ignoriert" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "IMAP-Konto · Belege fließen in Team „{0}\"" +msgstr "" + +#. placeholder {0}: source.teamName +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto · Team: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "IMAP-Konto verbinden" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Important: What This Means" msgstr "重要:这意味着什么" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "In dieses Team werden gefundene Belege einsortiert. Sie können das später nicht ändern — bei Bedarf eine neue Quelle anlegen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "In Gmail öffnen" +msgstr "" + #: apps/remix/app/components/tables/user-billing-organisations-table.tsx #: packages/lib/constants/billing.ts msgctxt "Subscription status" @@ -5847,6 +6240,10 @@ msgstr "包含:" msgid "Information" msgstr "信息" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Inhalt des Export-Pakets" +msgstr "" + #: packages/ui/components/recipient/recipient-action-auth-select.tsx msgid "Inherit authentication method" msgstr "继承认证方式" @@ -5937,8 +6334,8 @@ msgid "Invalid License Key" msgstr "许可证密钥无效" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Invalid License Type - Your NexaSign instance is using features that are not part of your license." -msgstr "许可证类型无效 - 您的 NexaSign 实例正在使用不在当前许可证范围内的功能。" +msgid "Invalid License Type - Your NexaFile instance is using features that are not part of your license." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Invalid link" @@ -6068,8 +6465,8 @@ msgid "Japanese" msgstr "日语" #: packages/email/templates/organisation-invite.tsx -msgid "Join {organisationName} on NexaSign" -msgstr "加入 {organisationName},使用 NexaSign" +msgid "Join {organisationName} on NexaFile" +msgstr "" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx @@ -6082,14 +6479,38 @@ msgstr "加入时间" msgid "Joined {0}" msgstr "加入时间 {0}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Kein Anhang" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Keine Belege im aktuellen Bereich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Keine Dateien im Archiv. Diese E-Mail wurde entweder vor Aktivierung des Archive-Features importiert oder enthielt keinen herunterladbaren Anhang (z. B. Beleg-Hinweis ohne PDF, der zum Portal verweist)." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kern: Wenn Sie <0>steuerrelevante Dokumente (Rechnungen, Verträge, Handelsbriefe) digital erzeugen oder ablegen, müssen sie <1>10 Jahre unveränderbar aufbewahrt und im Prüfungsfall dem Finanzamt zugänglich gemacht werden. Unterschriebene Verträge aus NexaFile fallen eindeutig unter diese Pflicht." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Key identifiers and relationships for this team." msgstr "此团队的关键标识符和关联关系。" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Kommandozeilen-Tool für den System-Administrator. Exportiert alle abgeschlossen signierten Envelopes, akzeptierten gefundenen Belege, Mail-/Anhang-Dateien und Audit-Logs eines Zeitraums als strukturiertes Paket." +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Korean" msgstr "韩语" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Korrespondent" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx #: apps/remix/app/components/forms/editor/editor-field-text-form.tsx #: apps/remix/app/components/general/document/document-attachments-popover.tsx @@ -6102,6 +6523,10 @@ msgstr "韩语" msgid "Label" msgstr "标签" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Laden" +msgstr "" + #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: apps/remix/app/components/general/menu-switcher.tsx @@ -6213,6 +6638,23 @@ msgstr "字间距" msgid "Letter Spacing" msgstr "字间距" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letzter Monat" +msgstr "" + +#. placeholder {0}: formatRelativeTime(latestSync, locale) +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Letzter Sync: {0}" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Letztes Quartal" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx #: apps/remix/app/components/general/admin-license-card.tsx msgid "License" @@ -6242,6 +6684,11 @@ msgstr "浅色模式" msgid "Like to have your own public profile with agreements?" msgstr "想拥有属于自己的公开协议页面吗?" +#. placeholder {0}: capabilities?.imap.maxAccountsPerUser +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Limit erreicht: maximal {0} IMAP-Konten pro Konto. Bestehende Quelle löschen, um eine neue anzulegen." +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Line height" msgstr "行高" @@ -6264,8 +6711,8 @@ msgid "Link template" msgstr "链接模板" #: packages/email/templates/organisation-account-link-confirmation.tsx -msgid "Link your NexaSign account" -msgstr "关联您的 NexaSign 账户" +msgid "Link your NexaFile account" +msgstr "" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx @@ -6337,6 +6784,14 @@ msgstr "正在查找表单字段" msgid "Looking for signature fields" msgstr "正在查找签名字段" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail erneut aus IMAP geladen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Mail-Inhalt" +msgstr "" + #: apps/remix/app/components/tables/admin-organisations-table.tsx #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/components/tables/organisation-teams-table.tsx @@ -6506,6 +6961,15 @@ msgstr "管理者" msgid "Managers and above" msgstr "管理者及以上" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Manuell" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Manuell zu ziehen" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "Mapping fields to recipients" msgstr "正在将字段映射到收件人" @@ -6609,8 +7073,8 @@ msgid "Min" msgstr "最小值" #: apps/remix/app/components/general/admin-license-status-banner.tsx -msgid "Missing License - Your NexaSign instance is using features that require a license." -msgstr "缺少许可证 - 您的 NexaSign 实例正在使用需要许可证的功能。" +msgid "Missing License - Your NexaFile instance is using features that require a license." +msgstr "" #: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx msgid "Missing Recipients" @@ -6702,6 +7166,10 @@ msgstr "我的文件夹" msgid "N/A" msgstr "N/A" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nach § 147 Abs. 6 AO kann das Finanzamt drei Arten von Datenzugriff fordern:" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/dialogs/assistant-confirmation-dialog.tsx #: apps/remix/app/components/dialogs/folder-update-dialog.tsx @@ -6762,6 +7230,14 @@ msgstr "需要签署" msgid "Needs to view" msgstr "需要查看" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Neu" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Neuen Sync-Lauf starten" +msgstr "" + #: apps/remix/app/components/tables/settings-security-passkey-table.tsx msgid "Never" msgstr "从不" @@ -6791,13 +7267,21 @@ msgstr "新选项 {0}" msgid "New Password" msgstr "新密码" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile ist Open-Source (AGPL-3.0). Die Bereitstellung erfolgt ohne Gewährleistung." +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx -msgid "NexaSign License" -msgstr "NexaSign 许可证" +msgid "NexaFile License" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "NexaFile stellt <0>GoBD-orientierte Archivfunktionen zur Verfügung. Die GoBD-konforme Gesamtimplementierung (Technik + Organisation + Verfahrensdokumentation) in Ihrem Unternehmen verantworten Sie selbst. Diese Seite dient der Orientierung und ersetzt keine Rechts-, Steuer- oder Konformitäts-Beratung. Wir empfehlen die Abstimmung mit Ihrer/m Steuerberater/in, Datenschutzbeauftragten und — für formale Zertifizierungen — mit einer/m Wirtschaftsprüfer/in." +msgstr "" #: apps/remix/app/components/dialogs/account-delete-dialog.tsx -msgid "NexaSign will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." -msgstr "NexaSign 将删除<0>你所有的文档,包括所有已完成的文档、签名以及属于你账号的其他所有资源。" +msgid "NexaFile will delete <0>all of your documents, along with all of your completed documents, signatures, and all other resources belonging to your Account." +msgstr "" #: apps/remix/app/components/dialogs/team-group-create-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx @@ -7005,6 +7489,18 @@ msgstr "未找到值。" msgid "No worries, it happens! Enter your email and we'll email you a special link to reset your password." msgstr "别担心,这很常见!输入你的邮箱,我们会给你发送一个用于重置密码的特殊链接。" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Noch kein Sync gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Noch keine Quelle verbunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Noch keine Sync-Läufe. Starten Sie oben einen Lauf." +msgstr "" + #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx #: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx #: apps/remix/app/components/forms/editor/editor-field-number-form.tsx @@ -7075,10 +7571,18 @@ msgstr "允许的团队数量。0 = 不限" msgid "Number Settings" msgstr "数字设置" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Nutzung" +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Off" msgstr "关闭" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Ohne TLS-Verifikation kann der Datenverkehr von einem Angreifer mitgelesen werden. Nur einsetzen, wenn der Server ein bekanntes selbst-signiertes Zertifikat hat." +msgstr "" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "On" msgstr "开启" @@ -7545,6 +8049,10 @@ msgstr "待处理的组织邀请" msgid "Pending since" msgstr "待处理起始时间" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Per FTP/SCP erreichbar. Dateien sind read-only (0440); zum Verschieben einer Kopie benutzen Sie `cp` statt `mv`." +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx msgid "per month" @@ -7573,6 +8081,10 @@ msgstr "个人账号" msgid "Personal Inbox" msgstr "个人收件箱" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Pfad auf dem Server" +msgstr "" + #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx msgid "Pick a number" @@ -7810,6 +8322,14 @@ msgstr "请上传一个 Logo" msgid "Polish" msgstr "波兰语" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Port" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Portal-Hinweis (Mail enthält)" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Portuguese (Brazil)" msgstr "葡萄牙语(巴西)" @@ -7824,6 +8344,14 @@ msgstr "X 轴位置:" msgid "Pos Y:" msgstr "Y 轴位置:" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach durchsuchen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Postfach-Durchsuchung gestartet" +msgstr "" + #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/general/document-signing/document-signing-mobile-widget.tsx @@ -7949,6 +8477,56 @@ msgstr "公共模板" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "公开模板与公开资料相关联。对公开模板的任何修改也会显示在你的公开资料中。" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle entfernt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quelle hinzugefügt" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle nicht gefunden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle reaktiviert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quelle verbinden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Quelle wirklich entfernen?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Quelle: <0>NexaStack — Open-Source-Vorlagen unter CC-BY 4.0. Feedback und Pull Requests willkommen." +msgstr "" + +#: apps/remix/app/components/general/settings-nav-desktop.tsx +#: apps/remix/app/components/general/settings-nav-mobile.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Quellen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Quellen verwalten" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "快速操作" @@ -7980,6 +8558,11 @@ msgstr "重新注册" msgid "Re-register Email Domain" msgstr "重新注册电子邮件域名" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Re-Sync fehlgeschlagen" +msgstr "" + #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx @@ -7994,8 +8577,8 @@ msgid "Read Only" msgstr "只读" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.support.tsx -msgid "Read our documentation to get started with NexaSign." -msgstr "阅读我们的文档,开始使用 NexaSign。" +msgid "Read our documentation to get started with NexaFile." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx msgid "Read Status" @@ -8014,6 +8597,14 @@ msgstr "正在读取您的文档" msgid "Ready" msgstr "就绪" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Reaktivieren fehlgeschlagen" +msgstr "" + #: apps/remix/app/routes/_internal+/[__htmltopdf]+/certificate.tsx #: packages/lib/server-only/pdf/render-certificate.ts msgid "Reason" @@ -8052,6 +8643,11 @@ msgstr "最近活动" msgid "Recent documents" msgstr "最近文档" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Rechnungs-Nr." +msgstr "" + #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/general/template/template-page-view-documents-table.tsx #: apps/remix/app/components/tables/documents-table.tsx @@ -8538,6 +9134,10 @@ msgstr "受限访问" msgid "Retention of Documents" msgstr "文档保留" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Retention-Check und Löschschutz" +msgstr "" + #: apps/remix/app/components/tables/admin-document-jobs-table.tsx msgid "Retried" msgstr "已重试次数" @@ -8569,8 +9169,8 @@ msgid "Return to Home" msgstr "返回首页" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx -msgid "Return to NexaSign sign in page here" -msgstr "在此返回 NexaSign 登录页面" +msgid "Return to NexaFile sign in page here" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/check-email.tsx #: apps/remix/app/routes/_unauthenticated+/reset-password._index.tsx @@ -9239,6 +9839,22 @@ msgstr "使用 Microsoft 注册" msgid "Sign Up with OIDC" msgstr "使用 OIDC 注册" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument geöffnet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument konnte nicht vorbereitet werden" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument öffnen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Signatur-Dokument vorbereitet" +msgstr "" + #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx #: apps/remix/app/components/embed/embed-direct-template-client-page.tsx #: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -9422,7 +10038,11 @@ msgid "Skip" msgstr "跳过" #: apps/remix/app/components/general/user-profile-timur.tsx -msgid "So könnte Ihr öffentliches NexaSign-Profil aussehen." +msgid "So könnte Ihr öffentliches NexaFile-Profil aussehen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Sobald ein IMAP-Konto verbunden ist, starten Sie gezielte Sync-Läufe für bestimmte Zeiträume. Gefundene Belege legt NexaFile im Eingang ab." msgstr "" #: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx @@ -9573,10 +10193,22 @@ msgstr "以空格分隔的域名列表。留空则允许所有域名。" msgid "Spanish" msgstr "西班牙语" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Speichern und synchronisieren" +msgstr "" + #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "SSO" msgstr "SSO" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Starten Sie in den Quellen-Einstellungen einen Sync-Lauf für einen bestimmten Zeitraum, um Belege aus Ihrem Postfach einzulesen." +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx msgid "Stats" msgstr "统计" @@ -9592,6 +10224,7 @@ msgstr "统计" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx #: apps/remix/app/routes/_internal+/[__htmltopdf]+/audit-log.tsx @@ -9754,6 +10387,14 @@ msgstr "通行密钥创建成功" msgid "Successfully created: {successCount}" msgstr "创建成功:{successCount}" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchbegriff" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Suchen…" +msgstr "" + #: packages/email/templates/bulk-send-complete.tsx msgid "Summary:" msgstr "摘要:" @@ -9790,6 +10431,18 @@ msgstr "同步失败,更改未保存" msgid "Sync license from server" msgstr "从服务器同步许可证" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf gestartet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Sync-Lauf konnte nicht starten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Sync-Lauf starten" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts #: packages/lib/utils/document-audit-logs.ts @@ -9814,14 +10467,15 @@ msgstr "目标组织" #: apps/remix/app/components/tables/organisation-teams-table.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "Team" msgstr "团队" #. placeholder {0}: team.name #: packages/lib/server-only/team/delete-team.ts -msgid "Team \"{0}\" has been deleted on NexaSign" -msgstr "团队“{0}”已在 NexaSign 上被删除" +msgid "Team \"{0}\" has been deleted on NexaFile" +msgstr "" #: packages/lib/constants/teams-translations.ts msgid "Team Admin" @@ -9831,6 +10485,10 @@ msgstr "团队管理员" msgid "Team Assignments" msgstr "团队分配" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Team auswählen" +msgstr "" + #: apps/remix/app/components/forms/subscription-claim-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Team Count" @@ -9872,8 +10530,8 @@ msgid "Team email removed" msgstr "团队邮箱已被移除" #: packages/email/templates/team-email-removed.tsx -msgid "Team email removed for {teamName} on NexaSign" -msgstr "NexaSign 上团队 {teamName} 的团队邮箱已被移除" +msgid "Team email removed for {teamName} on NexaFile" +msgstr "" #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx msgid "Team email verification" @@ -10087,7 +10745,6 @@ msgid "Template uploaded" msgstr "模板已上传" #: apps/remix/app/components/general/app-command-menu.tsx -#: apps/remix/app/components/general/app-nav-mobile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.public-profile.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx @@ -10108,6 +10765,11 @@ msgstr "模板已部分删除" msgid "Test" msgstr "测试" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Test fehlgeschlagen" +msgstr "" + #: apps/remix/app/components/dialogs/webhook-test-dialog.tsx msgid "Test Webhook" msgstr "测试 Webhook" @@ -10158,8 +10820,8 @@ msgid "Thank you for completing the signing process." msgstr "感谢您完成签署流程。" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx -msgid "Thank you for using NexaSign to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." -msgstr "感谢你使用 NexaSign 进行电子文档签署。本披露旨在向你说明在我们平台上使用电子签名的流程、合法性以及你的权利。选择使用电子签名,即表示你同意以下条款和条件。" +msgid "Thank you for using NexaFile to perform your electronic document signing. The purpose of this disclosure is to inform you about the process, legality, and your rights regarding the use of electronic signatures on our platform. By opting to use an electronic signature, you are agreeing to the terms and conditions outlined below." +msgstr "" #: packages/email/template-components/template-forgot-password.tsx msgid "That's okay, it happens! Click the button below to reset your password." @@ -10522,8 +11184,8 @@ msgstr "收件人在签署文档时允许使用的签名类型。" #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx -msgid "The URL for NexaSign to send webhook events to." -msgstr "NexaSign 向其发送 Webhook 事件的 URL。" +msgid "The URL for NexaFile to send webhook events to." +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "The user you are looking for may have been removed, renamed or may have never existed." @@ -10667,8 +11329,8 @@ msgid "This document has been signed by all recipients" msgstr "该文档已由所有收件人签署" #: apps/remix/app/components/general/document/document-certificate-qr-view.tsx -msgid "This document is available in your NexaSign account. You can view more details, recipients, and audit logs there." -msgstr "此文档在您的 NexaSign 账户中可用。您可以在那里查看更多详情、收件人和审计日志。" +msgid "This document is available in your NexaFile account. You can view more details, recipients, and audit logs there." +msgstr "" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document is currently a draft and has not been sent" @@ -10687,7 +11349,7 @@ msgid "This document was created using a direct link." msgstr "此文档是通过直接链接创建的。" #: packages/email/template-components/template-footer.tsx -msgid "This document was sent using NexaSign." +msgid "This document was sent using NexaFile." msgstr "" #: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx @@ -10904,6 +11566,10 @@ msgstr "标题" msgid "Title cannot be empty" msgstr "标题不能为空" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "TLS-Zertifikat prüfen" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "To accept this invitation you must create an account." msgstr "要接受此邀请,你必须创建一个账号。" @@ -11347,6 +12013,10 @@ msgstr "取消固定" msgid "Unsealed Documents" msgstr "未签章文档" +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Unterschriebene Verträge sind <0>steuerrelevante Belege — das Finanzamt darf sie bis zu 10 Jahre später prüfen. Hier finden Sie alle Bausteine, die NexaFile für eine <1>GoBD-orientierte Archivierung mitbringt: Erklärungen, Vorlagen, Tools, FAQ." +msgstr "" + #: apps/remix/app/components/general/user-profile-timur.tsx msgid "Unterzeichnen" msgstr "" @@ -11727,6 +12397,37 @@ msgstr "验证失败" msgid "Value" msgstr "值" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verarbeitet" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Verbinden Sie Ihre erste Dokumentenquelle" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Verbinden Sie Postfächer, aus denen Belege automatisch in den Eingang einlaufen sollen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung erfolgreich" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung fehlgeschlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Verbindung testen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vergangene Sync-Läufe" +msgstr "" + #: packages/email/template-components/template-access-auth-2fa.tsx msgid "Verification Code Required" msgstr "需要验证码" @@ -11782,6 +12483,10 @@ msgstr "垂直" msgid "Vertical Align" msgstr "垂直对齐" +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vertragsvorlagen für deutsche Unternehmen" +msgstr "" + #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx @@ -11963,6 +12668,27 @@ msgstr "查看中" msgid "Visibility" msgstr "可见性" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Von" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/_index.tsx +msgid "Vorlagen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Vorletztes Jahr" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wählen Sie einen Zeitraum aus. Belege aus diesem Zeitraum werden geprüft und in den Eingang importiert. Bereits importierte Belege werden automatisch übersprungen." +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Wählen Sie Quelle, Zeitraum und Suchbegriff. NexaFile liest passende Mails ein und legt Mail + Anhänge im Server-Archiv ab." +msgstr "" + #: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx msgid "Waiting" msgstr "等待中" @@ -11986,8 +12712,8 @@ msgstr "正在等待你的顺序" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx -msgid "Want to send slick signing links like this one? <0>Check out NexaSign." -msgstr "想要发送像这样顺畅好用的签署链接吗?<0>来了解一下 NexaSign。" +msgid "Want to send slick signing links like this one? <0>Check out NexaFile." +msgstr "" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "Want your own public profile?" @@ -12005,6 +12731,22 @@ msgstr "想拥有自己的公开资料吗?" msgid "Warning: Assistant as last signer" msgstr "警告:助理为最后一位签署人" +#: apps/remix/app/routes/_authenticated+/settings+/sources._index.tsx +msgid "Wartet auf ersten Sync" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was ist GoBD überhaupt?" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was NexaFile liefert" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/vorlagen+/gobd+/_index.tsx +msgid "Was Sie selbst regeln" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx msgid "We are unable to proceed to the billing portal at this time. Please try again, or contact support." @@ -12415,8 +13157,8 @@ msgid "Welcome to {organisationName}" msgstr "欢迎加入 {organisationName}" #: packages/email/template-components/template-confirmation-email.tsx -msgid "Welcome to NexaSign!" -msgstr "欢迎来到 NexaSign!" +msgid "Welcome to NexaFile!" +msgstr "" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Well-known URL is required" @@ -12454,8 +13196,8 @@ msgid "Whether to enable the SSO portal for your organisation" msgstr "是否为您的组织启用 SSO 门户" #: apps/remix/app/routes/_profile+/p.$url.tsx -msgid "While waiting for them to do so you can create your own NexaSign account and get started with document signing right away." -msgstr "在等待对方操作期间,你可以创建自己的 NexaSign 账号,立即开始使用文档签署功能。" +msgid "While waiting for them to do so you can create your own NexaFile account and get started with document signing right away." +msgstr "" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Whitelabeling, unlimited members and more" @@ -12470,6 +13212,10 @@ msgstr "你想提醒谁?" msgid "Width:" msgstr "宽度:" +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Wird abgebrochen…" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Withdrawing Consent" msgstr "撤回同意" @@ -12710,8 +13456,8 @@ msgid "You can only detect fields in draft envelopes" msgstr "您只能在草稿信封中检测字段" #: packages/email/templates/confirm-team-email.tsx -msgid "You can revoke access at any time in your team settings on NexaSign <0>here." -msgstr "你可以随时在 NexaSign 的团队设置中撤销访问权限,入口在<0>这里。" +msgid "You can revoke access at any time in your team settings on NexaFile <0>here." +msgstr "" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "You can update the profile URL by updating the team URL in the general settings page." @@ -12855,8 +13601,8 @@ msgstr "您已被 <0>{0} 邀请加入其组织。" #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts -msgid "You have been invited to join {0} on NexaSign" -msgstr "您已被邀请加入 NexaSign 上的 {0}" +msgid "You have been invited to join {0} on NexaFile" +msgstr "" #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" @@ -13406,12 +14152,12 @@ msgid "Your Email" msgstr "您的邮箱" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has already been confirmed. You can now use all features of NexaSign." -msgstr "您的邮箱已确认。您现在可以使用 NexaSign 的全部功能。" +msgid "Your email has already been confirmed. You can now use all features of NexaFile." +msgstr "" #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx -msgid "Your email has been successfully confirmed! You can now use all features of NexaSign." -msgstr "你的邮箱已成功确认!你现在可以使用 NexaSign 的所有功能。" +msgid "Your email has been successfully confirmed! You can now use all features of NexaFile." +msgstr "" #. placeholder {0}: teamEmail.team.name #. placeholder {1}: teamEmail.team.url @@ -13479,8 +14225,8 @@ msgid "Your plan does not support inviting members. Please upgrade or your plan msgstr "您的套餐不支持邀请成员。请升级您的套餐或通过 <0>{SUPPORT_EMAIL} 联系销售了解更多选项。" #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx -msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaSign." -msgstr "您的套餐已无效。请订阅新套餐以继续使用 NexaSign。" +msgid "Your plan is no longer valid. Please subscribe to a new plan to continue using NexaFile." +msgstr "" #: apps/remix/app/components/forms/profile.tsx msgid "Your profile has been updated successfully." @@ -13580,3 +14326,19 @@ msgstr "您的验证码:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "your-domain.com another-domain.com" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents._index.tsx +msgid "Zeitraum prüfen" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zum Signieren vorbereiten" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/find-documents.$id._index.tsx +msgid "Zurück" +msgstr "" + +#: apps/remix/app/routes/_authenticated+/settings+/sources.$id._index.tsx +msgid "Zurück zur Liste" +msgstr "" diff --git a/packages/lib/types/subscription.ts b/packages/lib/types/subscription.ts index 3952548..3edd9a4 100644 --- a/packages/lib/types/subscription.ts +++ b/packages/lib/types/subscription.ts @@ -9,7 +9,7 @@ import { ZOrganisationNameSchema } from '@nexasign/trpc/server/organisation-rout */ export const ZClaimFlagsSchema = z.object({ /** - * Allows disabling of NexaSign branding for: + * Allows disabling of NexaFile branding for: * - Certificates * - Emails * - Other? @@ -57,7 +57,7 @@ export const SUBSCRIPTION_CLAIM_FEATURE_FLAGS: Record< }, hidePoweredBy: { key: 'hidePoweredBy', - label: 'Hide NexaSign branding by', + label: 'Hide NexaFile branding by', }, emailDomains: { key: 'emailDomains', diff --git a/packages/lib/utils/authenticator.ts b/packages/lib/utils/authenticator.ts index b415135..58f69fd 100644 --- a/packages/lib/utils/authenticator.ts +++ b/packages/lib/utils/authenticator.ts @@ -9,7 +9,7 @@ export const getAuthenticatorOptions = () => { const rpId = webAppBaseUrl.hostname; return { - rpName: 'NexaSign', + rpName: 'NexaFile', rpId, origin: NEXT_PUBLIC_WEBAPP_URL(), timeout: PASSKEY_TIMEOUT, diff --git a/packages/prisma/migrations/20260429120000_add_discovery_document/migration.sql b/packages/prisma/migrations/20260429120000_add_discovery_document/migration.sql new file mode 100644 index 0000000..db60284 --- /dev/null +++ b/packages/prisma/migrations/20260429120000_add_discovery_document/migration.sql @@ -0,0 +1,183 @@ +-- Discovery — Schritt 1 des Lifecycles +-- Additive Migration: neue Tabellen, Enums und FKs für Discovery, Source und DiscoveryAuditLog. +-- Keine Mutation bestehender Daten außerhalb der drei Discovery-Tabellen. + +-- ============================================================================= +-- Enums +-- ============================================================================= + +CREATE TYPE "DiscoveryDocumentStatus" AS ENUM ( + 'INBOX', + 'PENDING_MANUAL', + 'ACCEPTED', + 'SIGNED', + 'ARCHIVED', + 'IGNORED' +); + +CREATE TYPE "SourceKind" AS ENUM ( + 'IMAP' +); + +CREATE TYPE "SourceSyncStatus" AS ENUM ( + 'PENDING', + 'SUCCESS', + 'FAILED', + 'SUSPENDED' +); + +CREATE TYPE "DiscoveryAuditEvent" AS ENUM ( + 'IMAP_ACCOUNT_CREATED', + 'IMAP_ACCOUNT_DELETED', + 'IMAP_ACCOUNT_UPDATED', + 'IMAP_SYNC_STARTED', + 'IMAP_SYNC_COMPLETED', + 'IMAP_SYNC_LOGIN_FAILED', + 'IMAP_SYNC_TLS_INSECURE', + 'IMAP_DOCUMENT_IMPORTED', + 'DISCOVERY_DOCUMENT_ACCEPTED', + 'DISCOVERY_DOCUMENT_IGNORED' +); + +-- ============================================================================= +-- Source — pro User konfigurierte Discovery-Quelle (IMAP, später Cloud). +-- ============================================================================= + +CREATE TABLE "Source" ( + "id" TEXT NOT NULL, + "userId" INTEGER NOT NULL, + "teamId" INTEGER NOT NULL, + "kind" "SourceKind" NOT NULL, + "label" TEXT NOT NULL, + "encryptedConfig" TEXT NOT NULL, + "encryptedConfigKeyVersion" TEXT NOT NULL DEFAULT 'v1', + "lastSyncAt" TIMESTAMP(3), + "lastSyncAttemptedAt" TIMESTAMP(3), + "lastSyncStatus" "SourceSyncStatus" NOT NULL DEFAULT 'PENDING', + "lastSyncError" TEXT, + "consecutiveFailures" INTEGER NOT NULL DEFAULT 0, + "syncLockUntil" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Source_pkey" PRIMARY KEY ("id") +); + +CREATE INDEX "Source_userId_idx" ON "Source"("userId"); +CREATE INDEX "Source_teamId_idx" ON "Source"("teamId"); +CREATE INDEX "Source_lastSyncAt_idx" ON "Source"("lastSyncAt"); +CREATE INDEX "Source_lastSyncAttemptedAt_idx" ON "Source"("lastSyncAttemptedAt"); + +-- ============================================================================= +-- DiscoveryDocument — Belege im Pre-Lifecycle-Eingang. +-- ============================================================================= + +CREATE TABLE "DiscoveryDocument" ( + "id" TEXT NOT NULL, + "teamId" INTEGER NOT NULL, + "uploadedById" INTEGER, + "sourceId" TEXT, + "title" TEXT NOT NULL, + "correspondent" TEXT, + "documentType" TEXT, + "documentDate" TIMESTAMP(3), + "capturedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "status" "DiscoveryDocumentStatus" NOT NULL DEFAULT 'INBOX', + "providerSource" TEXT NOT NULL, + "providerNativeId" TEXT, + "contentType" TEXT, + "fileSize" INTEGER, + "tags" TEXT[], + "detectedAmount" TEXT, + "detectedInvoiceNumber" TEXT, + "portalHint" TEXT, + "messageIdHash" TEXT, + "dataId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "DiscoveryDocument_pkey" PRIMARY KEY ("id") +); + +CREATE UNIQUE INDEX "DiscoveryDocument_dataId_key" ON "DiscoveryDocument"("dataId"); +CREATE INDEX "DiscoveryDocument_teamId_status_idx" ON "DiscoveryDocument"("teamId", "status"); +CREATE INDEX "DiscoveryDocument_teamId_capturedAt_idx" ON "DiscoveryDocument"("teamId", "capturedAt"); +CREATE INDEX "DiscoveryDocument_teamId_uploadedById_status_idx" ON "DiscoveryDocument"("teamId", "uploadedById", "status"); +CREATE INDEX "DiscoveryDocument_sourceId_idx" ON "DiscoveryDocument"("sourceId"); +CREATE INDEX "DiscoveryDocument_messageIdHash_idx" ON "DiscoveryDocument"("messageIdHash"); + +-- ============================================================================= +-- DiscoveryAuditLog — Audit-Spur für Source-Konfig und Lifecycle-Events. +-- ============================================================================= + +CREATE TABLE "DiscoveryAuditLog" ( + "id" TEXT NOT NULL, + "event" "DiscoveryAuditEvent" NOT NULL, + "sourceId" TEXT, + "discoveryDocumentId" TEXT, + "userId" INTEGER, + "teamId" INTEGER, + "metadata" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "DiscoveryAuditLog_pkey" PRIMARY KEY ("id") +); + +CREATE INDEX "DiscoveryAuditLog_sourceId_idx" ON "DiscoveryAuditLog"("sourceId"); +CREATE INDEX "DiscoveryAuditLog_discoveryDocumentId_idx" ON "DiscoveryAuditLog"("discoveryDocumentId"); +CREATE INDEX "DiscoveryAuditLog_userId_idx" ON "DiscoveryAuditLog"("userId"); +CREATE INDEX "DiscoveryAuditLog_createdAt_idx" ON "DiscoveryAuditLog"("createdAt"); + +-- ============================================================================= +-- Foreign Keys +-- ============================================================================= + +ALTER TABLE "Source" + ADD CONSTRAINT "Source_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "User"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +ALTER TABLE "Source" + ADD CONSTRAINT "Source_teamId_fkey" + FOREIGN KEY ("teamId") REFERENCES "Team"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryDocument" + ADD CONSTRAINT "DiscoveryDocument_teamId_fkey" + FOREIGN KEY ("teamId") REFERENCES "Team"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryDocument" + ADD CONSTRAINT "DiscoveryDocument_uploadedById_fkey" + FOREIGN KEY ("uploadedById") REFERENCES "User"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryDocument" + ADD CONSTRAINT "DiscoveryDocument_sourceId_fkey" + FOREIGN KEY ("sourceId") REFERENCES "Source"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryDocument" + ADD CONSTRAINT "DiscoveryDocument_dataId_fkey" + FOREIGN KEY ("dataId") REFERENCES "DocumentData"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryAuditLog" + ADD CONSTRAINT "DiscoveryAuditLog_sourceId_fkey" + FOREIGN KEY ("sourceId") REFERENCES "Source"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryAuditLog" + ADD CONSTRAINT "DiscoveryAuditLog_discoveryDocumentId_fkey" + FOREIGN KEY ("discoveryDocumentId") REFERENCES "DiscoveryDocument"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryAuditLog" + ADD CONSTRAINT "DiscoveryAuditLog_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "User"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + +ALTER TABLE "DiscoveryAuditLog" + ADD CONSTRAINT "DiscoveryAuditLog_teamId_fkey" + FOREIGN KEY ("teamId") REFERENCES "Team"("id") + ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/prisma/migrations/20260429160000_discovery_drift_fix/migration.sql b/packages/prisma/migrations/20260429160000_discovery_drift_fix/migration.sql new file mode 100644 index 0000000..f304672 --- /dev/null +++ b/packages/prisma/migrations/20260429160000_discovery_drift_fix/migration.sql @@ -0,0 +1,156 @@ +-- Discovery-Drift-Fix +-- Korrigiert fruehe NexaFILE-Beta-Installationen, bei denen die Discovery- +-- Basismigration schon als angewendet markiert wurde, aber noch nicht den +-- finalen V1-Stand enthielt oder nur teilweise angewendet war. + +-- ============================================================================= +-- 1. Fehlende Enums aus fruehen/teilweise angewendeten Beta-Migrationen +-- ============================================================================= + +DO $$ BEGIN + CREATE TYPE "SourceKind" AS ENUM ('IMAP'); +EXCEPTION WHEN duplicate_object THEN NULL; +END $$; + +DO $$ BEGIN + CREATE TYPE "SourceSyncStatus" AS ENUM ('PENDING', 'SUCCESS', 'FAILED', 'SUSPENDED'); +EXCEPTION WHEN duplicate_object THEN NULL; +END $$; + +DO $$ BEGIN + CREATE TYPE "DiscoveryAuditEvent" AS ENUM ( + 'IMAP_ACCOUNT_CREATED', + 'IMAP_ACCOUNT_DELETED', + 'IMAP_ACCOUNT_UPDATED', + 'IMAP_SYNC_STARTED', + 'IMAP_SYNC_COMPLETED', + 'IMAP_SYNC_LOGIN_FAILED', + 'IMAP_SYNC_TLS_INSECURE', + 'IMAP_DOCUMENT_IMPORTED', + 'DISCOVERY_DOCUMENT_ACCEPTED', + 'DISCOVERY_DOCUMENT_IGNORED' + ); +EXCEPTION WHEN duplicate_object THEN NULL; +END $$; + +-- ============================================================================= +-- 2. Fehlende Tabellen aus fruehen/teilweise angewendeten Beta-Migrationen +-- ============================================================================= + +CREATE TABLE IF NOT EXISTS "Source" ( + "id" TEXT NOT NULL, + "userId" INTEGER NOT NULL, + "teamId" INTEGER NOT NULL, + "kind" "SourceKind" NOT NULL, + "label" TEXT NOT NULL, + "encryptedConfig" TEXT NOT NULL, + "encryptedConfigKeyVersion" TEXT NOT NULL DEFAULT 'v1', + "lastSyncAt" TIMESTAMP(3), + "lastSyncAttemptedAt" TIMESTAMP(3), + "lastSyncStatus" "SourceSyncStatus" NOT NULL DEFAULT 'PENDING', + "lastSyncError" TEXT, + "consecutiveFailures" INTEGER NOT NULL DEFAULT 0, + "syncLockUntil" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Source_pkey" PRIMARY KEY ("id") +); + +CREATE TABLE IF NOT EXISTS "DiscoveryAuditLog" ( + "id" TEXT NOT NULL, + "event" "DiscoveryAuditEvent" NOT NULL, + "sourceId" TEXT, + "discoveryDocumentId" TEXT, + "userId" INTEGER, + "teamId" INTEGER, + "metadata" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "DiscoveryAuditLog_pkey" PRIMARY KEY ("id") +); + +-- ============================================================================= +-- 3. Spalten auf finalen V1-Stand bringen +-- ============================================================================= + +ALTER TABLE "Source" ADD COLUMN IF NOT EXISTS "teamId" INTEGER; + +-- Source wurde vor V1 nicht produktiv genutzt. Falls jemand trotzdem Beta-Daten +-- hat, ist ein leerer Stand reproduzierbarer als eine nicht migrierbare DB. +DELETE FROM "Source" WHERE "teamId" IS NULL; + +ALTER TABLE "Source" ALTER COLUMN "teamId" SET NOT NULL; + +ALTER TABLE "DiscoveryDocument" ADD COLUMN IF NOT EXISTS "sourceId" TEXT; +ALTER TABLE "DiscoveryDocument" ADD COLUMN IF NOT EXISTS "detectedAmount" TEXT; +ALTER TABLE "DiscoveryDocument" ADD COLUMN IF NOT EXISTS "detectedInvoiceNumber" TEXT; +ALTER TABLE "DiscoveryDocument" ADD COLUMN IF NOT EXISTS "portalHint" TEXT; +ALTER TABLE "DiscoveryDocument" ADD COLUMN IF NOT EXISTS "messageIdHash" TEXT; +ALTER TABLE "DiscoveryDocument" ALTER COLUMN "dataId" DROP NOT NULL; + +-- ============================================================================= +-- 4. Indizes +-- ============================================================================= + +CREATE INDEX IF NOT EXISTS "Source_userId_idx" ON "Source"("userId"); +CREATE INDEX IF NOT EXISTS "Source_teamId_idx" ON "Source"("teamId"); +CREATE INDEX IF NOT EXISTS "Source_lastSyncAt_idx" ON "Source"("lastSyncAt"); +CREATE INDEX IF NOT EXISTS "Source_lastSyncAttemptedAt_idx" ON "Source"("lastSyncAttemptedAt"); + +CREATE INDEX IF NOT EXISTS "DiscoveryDocument_teamId_uploadedById_status_idx" ON "DiscoveryDocument"("teamId", "uploadedById", "status"); +CREATE INDEX IF NOT EXISTS "DiscoveryDocument_sourceId_idx" ON "DiscoveryDocument"("sourceId"); +CREATE INDEX IF NOT EXISTS "DiscoveryDocument_messageIdHash_idx" ON "DiscoveryDocument"("messageIdHash"); + +CREATE INDEX IF NOT EXISTS "DiscoveryAuditLog_sourceId_idx" ON "DiscoveryAuditLog"("sourceId"); +CREATE INDEX IF NOT EXISTS "DiscoveryAuditLog_discoveryDocumentId_idx" ON "DiscoveryAuditLog"("discoveryDocumentId"); +CREATE INDEX IF NOT EXISTS "DiscoveryAuditLog_userId_idx" ON "DiscoveryAuditLog"("userId"); +CREATE INDEX IF NOT EXISTS "DiscoveryAuditLog_createdAt_idx" ON "DiscoveryAuditLog"("createdAt"); + +-- ============================================================================= +-- 5. Foreign Keys idempotent anlegen +-- ============================================================================= + +DO $$ BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'Source_userId_fkey') THEN + ALTER TABLE "Source" ADD CONSTRAINT "Source_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "User"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + END IF; + + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'Source_teamId_fkey') THEN + ALTER TABLE "Source" ADD CONSTRAINT "Source_teamId_fkey" + FOREIGN KEY ("teamId") REFERENCES "Team"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + END IF; + + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'DiscoveryDocument_sourceId_fkey') THEN + ALTER TABLE "DiscoveryDocument" ADD CONSTRAINT "DiscoveryDocument_sourceId_fkey" + FOREIGN KEY ("sourceId") REFERENCES "Source"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + END IF; + + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'DiscoveryAuditLog_sourceId_fkey') THEN + ALTER TABLE "DiscoveryAuditLog" ADD CONSTRAINT "DiscoveryAuditLog_sourceId_fkey" + FOREIGN KEY ("sourceId") REFERENCES "Source"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + END IF; + + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'DiscoveryAuditLog_discoveryDocumentId_fkey') THEN + ALTER TABLE "DiscoveryAuditLog" ADD CONSTRAINT "DiscoveryAuditLog_discoveryDocumentId_fkey" + FOREIGN KEY ("discoveryDocumentId") REFERENCES "DiscoveryDocument"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + END IF; + + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'DiscoveryAuditLog_userId_fkey') THEN + ALTER TABLE "DiscoveryAuditLog" ADD CONSTRAINT "DiscoveryAuditLog_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "User"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + END IF; + + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'DiscoveryAuditLog_teamId_fkey') THEN + ALTER TABLE "DiscoveryAuditLog" ADD CONSTRAINT "DiscoveryAuditLog_teamId_fkey" + FOREIGN KEY ("teamId") REFERENCES "Team"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + END IF; +END $$; diff --git a/packages/prisma/migrations/20260429180000_sync_run_model/migration.sql b/packages/prisma/migrations/20260429180000_sync_run_model/migration.sql new file mode 100644 index 0000000..a78a4d1 --- /dev/null +++ b/packages/prisma/migrations/20260429180000_sync_run_model/migration.sql @@ -0,0 +1,67 @@ +-- Sync-Run-Modell: User-getriggerte Sync-Läufe statt Cron-Auto-Sync +-- +-- Änderungen: +-- 1. Neue Tabelle SyncRun + Enum SyncRunStatus +-- 2. Source.lastSyncAttemptedAt + syncLockUntil DROP — Lock kommt jetzt +-- aus laufendem SyncRun (status = RUNNING) + +-- ============================================================================= +-- 1. SyncRunStatus Enum +-- ============================================================================= + +CREATE TYPE "SyncRunStatus" AS ENUM ( + 'PENDING', + 'RUNNING', + 'SUCCESS', + 'FAILED', + 'CANCELLED' +); + +-- ============================================================================= +-- 2. SyncRun Tabelle +-- ============================================================================= + +CREATE TABLE "SyncRun" ( + "id" TEXT NOT NULL, + "sourceId" TEXT NOT NULL, + "triggeredById" INTEGER NOT NULL, + "rangeFrom" TIMESTAMP(3) NOT NULL, + "rangeTo" TIMESTAMP(3) NOT NULL, + "status" "SyncRunStatus" NOT NULL DEFAULT 'PENDING', + "mailsChecked" INTEGER NOT NULL DEFAULT 0, + "documentsAuto" INTEGER NOT NULL DEFAULT 0, + "documentsManual" INTEGER NOT NULL DEFAULT 0, + "documentsIgnored" INTEGER NOT NULL DEFAULT 0, + "documentsFailed" INTEGER NOT NULL DEFAULT 0, + "errorMessage" TEXT, + "cancelRequested" BOOLEAN NOT NULL DEFAULT false, + "startedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "finishedAt" TIMESTAMP(3), + + CONSTRAINT "SyncRun_pkey" PRIMARY KEY ("id") +); + +CREATE INDEX "SyncRun_sourceId_startedAt_idx" ON "SyncRun"("sourceId", "startedAt" DESC); +CREATE INDEX "SyncRun_status_idx" ON "SyncRun"("status"); +CREATE UNIQUE INDEX "SyncRun_one_active_per_source_idx" + ON "SyncRun"("sourceId") + WHERE "status" IN ('PENDING', 'RUNNING'); + +ALTER TABLE "SyncRun" + ADD CONSTRAINT "SyncRun_sourceId_fkey" + FOREIGN KEY ("sourceId") REFERENCES "Source"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +ALTER TABLE "SyncRun" + ADD CONSTRAINT "SyncRun_triggeredById_fkey" + FOREIGN KEY ("triggeredById") REFERENCES "User"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +-- ============================================================================= +-- 3. Source aufräumen — Cron-Cursor und Lock-Felder raus +-- ============================================================================= + +DROP INDEX IF EXISTS "Source_lastSyncAttemptedAt_idx"; + +ALTER TABLE "Source" DROP COLUMN IF EXISTS "lastSyncAttemptedAt"; +ALTER TABLE "Source" DROP COLUMN IF EXISTS "syncLockUntil"; diff --git a/packages/prisma/migrations/20260429190000_archive_artifacts/migration.sql b/packages/prisma/migrations/20260429190000_archive_artifacts/migration.sql new file mode 100644 index 0000000..6fccf06 --- /dev/null +++ b/packages/prisma/migrations/20260429190000_archive_artifacts/migration.sql @@ -0,0 +1,59 @@ +-- Archive-Artifacts + WORM-Lifecycle +-- +-- 1. DiscoveryArtifact-Tabelle: pro Datei im Archiv-Ordner ein DB-Eintrag mit +-- sha256-Hash. GoBD-Beweisfähigkeit für Mail/Body/Anhänge. +-- 2. DiscoveryDocument: bodyText (Klartext für UI), bodyHasHtml-Hint, archivePath +-- (Filesystem-Ordner), acceptedAt + acceptedById (GoBD-Retention-Anker). + +-- ============================================================================= +-- 1. Enum + Tabelle +-- ============================================================================= + +CREATE TYPE "DiscoveryArtifactKind" AS ENUM ( + 'MAIL_EML', + 'MAIL_BODY_TEXT', + 'MAIL_BODY_HTML', + 'MAIL_METADATA', + 'ATTACHMENT' +); + +CREATE TABLE "DiscoveryArtifact" ( + "id" TEXT NOT NULL, + "discoveryDocumentId" TEXT NOT NULL, + "kind" "DiscoveryArtifactKind" NOT NULL, + "fileName" TEXT NOT NULL, + "contentType" TEXT NOT NULL, + "fileSize" INTEGER NOT NULL, + "sha256" VARCHAR(64) NOT NULL, + "relativePath" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "DiscoveryArtifact_pkey" PRIMARY KEY ("id") +); + +CREATE UNIQUE INDEX "DiscoveryArtifact_discoveryDocumentId_kind_fileName_key" + ON "DiscoveryArtifact"("discoveryDocumentId", "kind", "fileName"); +CREATE INDEX "DiscoveryArtifact_discoveryDocumentId_idx" ON "DiscoveryArtifact"("discoveryDocumentId"); +CREATE INDEX "DiscoveryArtifact_sha256_idx" ON "DiscoveryArtifact"("sha256"); + +ALTER TABLE "DiscoveryArtifact" + ADD CONSTRAINT "DiscoveryArtifact_discoveryDocumentId_fkey" + FOREIGN KEY ("discoveryDocumentId") REFERENCES "DiscoveryDocument"("id") + ON DELETE CASCADE ON UPDATE CASCADE; + +-- ============================================================================= +-- 2. DiscoveryDocument-Erweiterung +-- ============================================================================= + +ALTER TABLE "DiscoveryDocument" ADD COLUMN "bodyText" TEXT; +ALTER TABLE "DiscoveryDocument" ADD COLUMN "bodyHasHtml" BOOLEAN NOT NULL DEFAULT false; +ALTER TABLE "DiscoveryDocument" ADD COLUMN "archivePath" TEXT; +ALTER TABLE "DiscoveryDocument" ADD COLUMN "acceptedAt" TIMESTAMP(3); +ALTER TABLE "DiscoveryDocument" ADD COLUMN "acceptedById" INTEGER; + +CREATE INDEX "DiscoveryDocument_acceptedAt_idx" ON "DiscoveryDocument"("acceptedAt"); + +ALTER TABLE "DiscoveryDocument" + ADD CONSTRAINT "DiscoveryDocument_acceptedById_fkey" + FOREIGN KEY ("acceptedById") REFERENCES "User"("id") + ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/packages/prisma/migrations/20260430080000_dedupe_discovery_documents/migration.sql b/packages/prisma/migrations/20260430080000_dedupe_discovery_documents/migration.sql new file mode 100644 index 0000000..048e8e3 --- /dev/null +++ b/packages/prisma/migrations/20260430080000_dedupe_discovery_documents/migration.sql @@ -0,0 +1,78 @@ +-- Dedupe DiscoveryDocument rows pro (sourceId, messageIdHash) und schliesse die +-- Race-Lücke per echtem Unique-Constraint. +-- +-- Ursache: Der App-seitige Idempotenz-Check in +-- packages/lib/server-only/sources/imap/imap-source-adapter.ts macht ein +-- findFirst() VOR dem create(). Bei parallel laufenden Sync-Runs (oder einem +-- abgebrochenen + neu gestarteten Run) sehen beide den Datensatz noch nicht, +-- beide schreiben — und in der UI tauchen Belege doppelt auf. +-- +-- Diese Migration: +-- 1) Konsolidiert die existierenden Duplikate: per (sourceId, messageIdHash) +-- bleibt genau eine Zeile uebrig — bevorzugt die bereits Akzeptierte +-- (acceptedAt IS NOT NULL), sonst die mit der frühesten createdAt. +-- 2) Re-targeted Audit-Logs der zu loeschenden Duplikate auf den verbleibenden +-- Datensatz, damit kein History-Eintrag verloren geht. +-- 3) Loescht die ueberzaehligen Zeilen. DiscoveryArtifact cascadiert +-- automatisch (onDelete Cascade), DocumentData bleibt orphaned und kann +-- separat geprunet werden. +-- 4) Setzt den fehlenden Unique-Constraint, damit zukuenftige Race-Inserts +-- hart auf P2002 laufen. +-- +-- Die Operationen laufen in einer Transaktion via Prisma-Migration-Wrapper. + +-- 1) Identifiziere Duplikate, waehle den "Keeper" pro Gruppe. +WITH ranked AS ( + SELECT + id, + "sourceId", + "messageIdHash", + "acceptedAt", + "createdAt", + ROW_NUMBER() OVER ( + PARTITION BY "sourceId", "messageIdHash" + -- Akzeptierte zuerst (NULLS LAST), dann aelteste + ORDER BY ("acceptedAt" IS NOT NULL) DESC, "createdAt" ASC, id ASC + ) AS rnk + FROM "DiscoveryDocument" + WHERE "messageIdHash" IS NOT NULL AND "sourceId" IS NOT NULL +), +keepers AS ( + SELECT "sourceId", "messageIdHash", id AS keeper_id + FROM ranked + WHERE rnk = 1 +), +losers AS ( + SELECT r.id AS loser_id, k.keeper_id + FROM ranked r + JOIN keepers k ON k."sourceId" = r."sourceId" AND k."messageIdHash" = r."messageIdHash" + WHERE r.rnk > 1 +) + +-- 2) Audit-Logs der Duplikate auf den Keeper umhaengen. +UPDATE "DiscoveryAuditLog" al +SET "discoveryDocumentId" = l.keeper_id +FROM losers l +WHERE al."discoveryDocumentId" = l.loser_id; + +-- 3) Duplikate loeschen. DiscoveryArtifact cascadiert (onDelete Cascade in Prisma). +WITH ranked AS ( + SELECT + id, + ROW_NUMBER() OVER ( + PARTITION BY "sourceId", "messageIdHash" + ORDER BY ("acceptedAt" IS NOT NULL) DESC, "createdAt" ASC, id ASC + ) AS rnk + FROM "DiscoveryDocument" + WHERE "messageIdHash" IS NOT NULL AND "sourceId" IS NOT NULL +) +DELETE FROM "DiscoveryDocument" +WHERE id IN (SELECT id FROM ranked WHERE rnk > 1); + +-- 4) Unique-Constraint setzen: ab jetzt schlaegt der zweite Insert hart fehl +-- (Prisma P2002), kein silent dup mehr. NULL-Werte bleiben erlaubt — der +-- Constraint greift nur, wenn beide Felder gesetzt sind, was Postgres auch +-- per Default-Verhalten so handhabt (zwei NULL gelten nicht als gleich). +CREATE UNIQUE INDEX "DiscoveryDocument_sourceId_messageIdHash_key" + ON "DiscoveryDocument"("sourceId", "messageIdHash") + WHERE "sourceId" IS NOT NULL AND "messageIdHash" IS NOT NULL; diff --git a/packages/prisma/migrations/20260430100000_add_imap_resync_audit_event/migration.sql b/packages/prisma/migrations/20260430100000_add_imap_resync_audit_event/migration.sql new file mode 100644 index 0000000..c75cda1 --- /dev/null +++ b/packages/prisma/migrations/20260430100000_add_imap_resync_audit_event/migration.sql @@ -0,0 +1,4 @@ +-- Audit-Event fuer „User hat einzelne Mail aus IMAP nachgeladen" — Aktion +-- aus der Beleg-Detail-Seite, die ein Document, das vor Aktivierung des +-- Archive-Features importiert wurde, mit echten Files nachfuettert. +ALTER TYPE "DiscoveryAuditEvent" ADD VALUE 'IMAP_DOCUMENT_RESYNCED'; diff --git a/packages/prisma/migrations/20260430120000_link_discovery_to_signing_envelope/migration.sql b/packages/prisma/migrations/20260430120000_link_discovery_to_signing_envelope/migration.sql new file mode 100644 index 0000000..0edce98 --- /dev/null +++ b/packages/prisma/migrations/20260430120000_link_discovery_to_signing_envelope/migration.sql @@ -0,0 +1,21 @@ +-- NexaFILE Schritt 2 -> 3: ein gefundener Beleg kann ein normales +-- Signatur-Dokument erzeugen. Der Link macht die Aktion idempotent und +-- erlaubt der UI, das bereits vorbereitete Dokument wieder zu öffnen. + +ALTER TYPE "DiscoveryAuditEvent" ADD VALUE 'DISCOVERY_SIGNING_DOCUMENT_CREATED'; + +ALTER TABLE "DiscoveryDocument" + ADD COLUMN "signingEnvelopeId" TEXT; + +CREATE UNIQUE INDEX "DiscoveryDocument_signingEnvelopeId_key" + ON "DiscoveryDocument"("signingEnvelopeId"); + +ALTER TABLE "DiscoveryDocument" + ADD CONSTRAINT "DiscoveryDocument_signingEnvelopeId_fkey" + FOREIGN KEY ("signingEnvelopeId") REFERENCES "Envelope"("id") + ON DELETE SET NULL ON UPDATE CASCADE; + +-- User-sichtbarer Suchbegriff fuer manuelle Postfach-Durchlaeufe +-- (z. B. "Rechnung", "invoice", "Beleg"). +ALTER TABLE "SyncRun" + ADD COLUMN "searchTerm" TEXT; diff --git a/packages/prisma/migrations/20260430130000_backfill_discovery_retention_start/migration.sql b/packages/prisma/migrations/20260430130000_backfill_discovery_retention_start/migration.sql new file mode 100644 index 0000000..817eca3 --- /dev/null +++ b/packages/prisma/migrations/20260430130000_backfill_discovery_retention_start/migration.sql @@ -0,0 +1,64 @@ +-- Backfill fuer Discovery-Belege, die vor der GoBD-Brueckenlogik bereits +-- archiviert oder in ein Signatur-Dokument uebernommen wurden, aber noch +-- keinen acceptedAt-Retention-Start hatten. + +WITH candidates AS ( + SELECT + id, + "teamId", + "uploadedById", + status, + "signingEnvelopeId", + COALESCE("updatedAt", "capturedAt", "createdAt", NOW()) AS retention_start + FROM "DiscoveryDocument" + WHERE "acceptedAt" IS NULL + AND ( + status IN ('ACCEPTED', 'SIGNED', 'ARCHIVED') + OR "signingEnvelopeId" IS NOT NULL + ) +), +updated AS ( + UPDATE "DiscoveryDocument" d + SET + "acceptedAt" = c.retention_start, + "acceptedById" = COALESCE(d."acceptedById", c."uploadedById"), + status = CASE + WHEN d.status = 'ARCHIVED' THEN d.status + WHEN d."signingEnvelopeId" IS NOT NULL THEN 'SIGNED' + ELSE d.status + END + FROM candidates c + WHERE d.id = c.id + RETURNING + d.id, + d."teamId", + d."uploadedById", + d.status, + d."providerSource", + d."signingEnvelopeId", + c.retention_start +) +INSERT INTO "DiscoveryAuditLog" ( + id, + event, + "discoveryDocumentId", + "userId", + "teamId", + metadata, + "createdAt" +) +SELECT + 'disc_audit_backfill_' || id, + 'DISCOVERY_DOCUMENT_ACCEPTED', + id, + "uploadedById", + "teamId", + jsonb_build_object( + 'action', CASE WHEN "signingEnvelopeId" IS NOT NULL THEN 'create-signing-document' ELSE 'archive' END, + 'providerSource', "providerSource", + 'signingEnvelopeId', "signingEnvelopeId", + 'retentionStarted', true, + 'backfilled', true + ), + retention_start +FROM updated; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 2f44014..8a23263 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -66,6 +66,12 @@ model User { folders Folder[] envelopes Envelope[] + uploadedDiscoveryDocuments DiscoveryDocument[] + acceptedDiscoveryDocuments DiscoveryDocument[] @relation("DiscoveryDocumentAcceptedBy") + sources Source[] + triggeredSyncRuns SyncRun[] + discoveryAuditLogs DiscoveryAuditLog[] + verificationTokens VerificationToken[] apiTokens ApiToken[] securityAuditLogs UserSecurityAuditLog[] @@ -436,6 +442,7 @@ model Envelope { documentMeta DocumentMeta @relation(fields: [documentMetaId], references: [id]) envelopeAttachments EnvelopeAttachment[] + discoverySourceDocument DiscoveryDocument? @relation("DiscoveryDocumentSigningEnvelope") @@index([type]) @@index([status]) @@ -495,11 +502,12 @@ enum DocumentSigningOrder { } model DocumentData { - id String @id @default(cuid()) - type DocumentDataType - data String - initialData String - envelopeItem EnvelopeItem? + id String @id @default(cuid()) + type DocumentDataType + data String + initialData String + envelopeItem EnvelopeItem? + discoveryDocument DiscoveryDocument? } enum DocumentDistributionMethod { @@ -930,6 +938,9 @@ model Team { apiTokens ApiToken[] webhooks Webhook[] teamGroups TeamGroup[] + discoveryDocuments DiscoveryDocument[] + discoveryAuditLogs DiscoveryAuditLog[] + sources Source[] organisationId String organisation Organisation @relation(fields: [organisationId], references: [id], onDelete: Cascade) @@ -1121,3 +1132,249 @@ model RateLimit { @@id([key, action, bucket]) @@index([createdAt]) } + +// ----------------------------------------------------------------------------- +// Discovery — Schritt 1 des Lifecycles („Dokumente finden") +// ----------------------------------------------------------------------------- +// Ein DiscoveryDocument ist ein im System aufgetauchter Beleg, bevor er in den +// Lifecycle übernommen wird (Schritt 3 = signieren). Pro Team isoliert. +// Die Bytes liegen in DocumentData (Reuse des bestehenden Storage-Providers). + +enum DiscoveryDocumentStatus { + INBOX + PENDING_MANUAL + ACCEPTED + SIGNED + ARCHIVED + IGNORED +} + +model DiscoveryDocument { + id String @id @default(cuid()) + teamId Int + team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) + uploadedById Int? + uploadedBy User? @relation(fields: [uploadedById], references: [id], onDelete: SetNull) + sourceId String? + source Source? @relation(fields: [sourceId], references: [id], onDelete: SetNull) + + title String + correspondent String? + documentType String? + documentDate DateTime? + capturedAt DateTime @default(now()) + + status DiscoveryDocumentStatus @default(INBOX) + + providerSource String // "local", "imap", "paperless", ... + providerNativeId String? + + contentType String? + fileSize Int? + tags String[] + + // Strukturierte Felder aus der Klassifizierung. + detectedAmount String? + detectedInvoiceNumber String? + portalHint String? + messageIdHash String? + + // Mail-Body als Klartext (HTML-stripped) für UI-Anzeige. Begrenzt auf 1 MB. + // Originale .eml + body.html liegen als Artifacts auf dem Filesystem. + bodyText String? @db.Text + // Hint für UI: HTML-Variante existiert als Datei, wird NICHT inline gerendert. + bodyHasHtml Boolean @default(false) + // Pfad zum Filesystem-Ordner mit eml/body/attachments/metadata. + // Relative zu NEXT_PRIVATE_DISCOVERY_ARCHIVE_PATH. + archivePath String? + + // GoBD-Lifecycle: ab acceptedAt zählt 10-Jahres-Retention, WORM aktiv. + acceptedAt DateTime? + acceptedById Int? + acceptedBy User? @relation("DiscoveryDocumentAcceptedBy", fields: [acceptedById], references: [id], onDelete: SetNull) + + // dataId ist optional, weil MANUAL-Belege (Beleg-Hinweis ohne PDF, User muss + // im Portal nachziehen) keine Bytes haben. Lokale Uploads und IMAP-AUTO- + // Imports haben weiterhin dataId. + dataId String? @unique + data DocumentData? @relation(fields: [dataId], references: [id], onDelete: Cascade) + + // Optionaler Link in Schritt 3 des NexaFILE-Flows: aus einem gefundenen + // Beleg wurde ein normales Signatur-Dokument erzeugt. + signingEnvelopeId String? @unique + signingEnvelope Envelope? @relation("DiscoveryDocumentSigningEnvelope", fields: [signingEnvelopeId], references: [id], onDelete: SetNull) + + auditLogs DiscoveryAuditLog[] + artifacts DiscoveryArtifact[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([teamId, status]) + @@index([teamId, capturedAt]) + @@index([teamId, uploadedById, status]) + @@index([sourceId]) + @@index([messageIdHash]) + @@index([acceptedAt]) + + // Idempotenz-Constraint: pro Source darf jede Message-ID nur einmal vorkommen. + // Schliesst die Race-Luecke des App-seitigen findFirst-vor-create-Patterns im + // IMAP-Adapter (verifiziert 2026-04-30 nach doppelten Receipts in der Beleg-Inbox). + // Implementiert als PARTIAL-Unique-Index (excludes NULL) in der Migration + // 20260430080000_dedupe_discovery_documents — Prisma kann partial indexes nicht + // per @@unique-Direktive ausdruecken, daher hier nur als Kommentar dokumentiert. +} + +enum DiscoveryArtifactKind { + MAIL_EML + MAIL_BODY_TEXT + MAIL_BODY_HTML + MAIL_METADATA + ATTACHMENT +} + +// DiscoveryArtifact — eine Datei im Archiv-Ordner einer DiscoveryDocument. +// Pro Mail entstehen typisch: 1× MAIL_EML, 1× MAIL_BODY_TEXT, 1× MAIL_METADATA, +// 0..1× MAIL_BODY_HTML, 0..N× ATTACHMENT. sha256 ist Pflicht — GoBD-Beweis. +model DiscoveryArtifact { + id String @id @default(cuid()) + discoveryDocumentId String + discoveryDocument DiscoveryDocument @relation(fields: [discoveryDocumentId], references: [id], onDelete: Cascade) + kind DiscoveryArtifactKind + fileName String + contentType String + fileSize Int + sha256 String @db.VarChar(64) + // Pfad relativ zu DiscoveryDocument.archivePath (z. B. "attachment-1.pdf"). + relativePath String + createdAt DateTime @default(now()) + + @@unique([discoveryDocumentId, kind, fileName]) + @@index([discoveryDocumentId]) + @@index([sha256]) +} + +// ----------------------------------------------------------------------------- +// Source — pro User konfigurierte Discovery-Quelle (IMAP, später Cloud). +// ----------------------------------------------------------------------------- + +enum SourceKind { + IMAP +} + +enum SourceSyncStatus { + PENDING + SUCCESS + FAILED + SUSPENDED +} + +model Source { + id String @id @default(cuid()) + userId Int + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + // teamId ist Pflicht: User entscheidet beim Anlegen, in welches Team die + // gefundenen Belege fließen. Das verhindert Belege im falschen Team-Kontext + // bei Multi-Team-Mitgliedschaft. + teamId Int + team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) + kind SourceKind + label String + encryptedConfig String @db.Text + encryptedConfigKeyVersion String @default("v1") + // lastSyncAt = finishedAt vom letzten erfolgreichen SyncRun (Anzeige). + // Lock kommt nicht mehr aus Source.syncLockUntil, sondern aus dem laufenden + // SyncRun (status = RUNNING). lastSyncAttemptedAt entfällt komplett. + lastSyncAt DateTime? + lastSyncStatus SourceSyncStatus @default(PENDING) + lastSyncError String? + consecutiveFailures Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + discoveryDocuments DiscoveryDocument[] + auditLogs DiscoveryAuditLog[] + syncRuns SyncRun[] + + @@index([userId]) + @@index([teamId]) + @@index([lastSyncAt]) +} + +enum SyncRunStatus { + PENDING + RUNNING + SUCCESS + FAILED + CANCELLED +} + +// SyncRun — eine vom User getriggerte Suche über einen expliziten Zeitraum. +// Idempotenz beim Mehrfach-Trigger: messageIdHash auf DiscoveryDocument +// verhindert Duplikate, wenn überlappende Zeiträume gewählt werden. +model SyncRun { + id String @id @default(cuid()) + sourceId String + source Source @relation(fields: [sourceId], references: [id], onDelete: Cascade) + triggeredById Int + triggeredBy User @relation(fields: [triggeredById], references: [id], onDelete: Cascade) + + rangeFrom DateTime + rangeTo DateTime + searchTerm String? + status SyncRunStatus @default(PENDING) + + mailsChecked Int @default(0) + documentsAuto Int @default(0) + documentsManual Int @default(0) + documentsIgnored Int @default(0) + documentsFailed Int @default(0) + + errorMessage String? + cancelRequested Boolean @default(false) + + startedAt DateTime @default(now()) + finishedAt DateTime? + + @@index([sourceId, startedAt(sort: Desc)]) + @@index([status]) +} + +// ----------------------------------------------------------------------------- +// DiscoveryAuditLog — Audit-Spur für Source-Konfig und Discovery-Lifecycle. +// ----------------------------------------------------------------------------- + +enum DiscoveryAuditEvent { + IMAP_ACCOUNT_CREATED + IMAP_ACCOUNT_DELETED + IMAP_ACCOUNT_UPDATED + IMAP_SYNC_STARTED + IMAP_SYNC_COMPLETED + IMAP_SYNC_LOGIN_FAILED + IMAP_SYNC_TLS_INSECURE + IMAP_DOCUMENT_IMPORTED + IMAP_DOCUMENT_RESYNCED + DISCOVERY_DOCUMENT_ACCEPTED + DISCOVERY_DOCUMENT_IGNORED + DISCOVERY_SIGNING_DOCUMENT_CREATED +} + +model DiscoveryAuditLog { + id String @id @default(cuid()) + event DiscoveryAuditEvent + sourceId String? + source Source? @relation(fields: [sourceId], references: [id], onDelete: SetNull) + discoveryDocumentId String? + discoveryDocument DiscoveryDocument? @relation(fields: [discoveryDocumentId], references: [id], onDelete: SetNull) + userId Int? + user User? @relation(fields: [userId], references: [id], onDelete: SetNull) + teamId Int? + team Team? @relation(fields: [teamId], references: [id], onDelete: SetNull) + metadata Json? + createdAt DateTime @default(now()) + + @@index([sourceId]) + @@index([discoveryDocumentId]) + @@index([userId]) + @@index([createdAt]) +} diff --git a/packages/trpc/server/discovery-router/router.ts b/packages/trpc/server/discovery-router/router.ts new file mode 100644 index 0000000..10fd3f2 --- /dev/null +++ b/packages/trpc/server/discovery-router/router.ts @@ -0,0 +1,514 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { EnvelopeType } from '@prisma/client'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; + +import { AppError, AppErrorCode } from '@nexasign/lib/errors/app-error'; +import { getDiscoveryReader, isDiscoveryConfigured } from '@nexasign/lib/server-only/discovery'; +import { createEnvelope } from '@nexasign/lib/server-only/envelope/create-envelope'; +import { getAbsoluteArchivePath } from '@nexasign/lib/server-only/sources/archive'; +import { resyncSingleDocument } from '@nexasign/lib/server-only/sources/imap'; +import { putNormalizedPdfFileServerSide } from '@nexasign/lib/universal/upload/put-file.server'; +import { prisma } from '@nexasign/prisma'; + +import { authenticatedProcedure, router } from '../trpc'; +import { + ZCreateSigningDocumentRequestSchema, + ZCreateSigningDocumentResponseSchema, + ZFindDiscoveryDocumentsRequestSchema, + ZFindDiscoveryDocumentsResponseSchema, + ZGetDiscoveryDocumentRequestSchema, + ZGetDiscoveryDocumentResponseSchema, + ZGetDocumentDetailRequestSchema, + ZGetDocumentDetailResponseSchema, + ZResyncSingleDocumentRequestSchema, + ZResyncSingleDocumentResponseSchema, + ZUpdateDiscoveryDocumentStatusRequestSchema, + ZUpdateDiscoveryDocumentStatusResponseSchema, +} from './schema'; + +const ACTION_STATUS_MAP = { + accept: 'ACCEPTED', + 'mark-pending-manual': 'PENDING_MANUAL', + archive: 'ARCHIVED', + ignore: 'IGNORED', +} as const; + +const ACTION_AUDIT_MAP = { + accept: 'DISCOVERY_DOCUMENT_ACCEPTED', + 'mark-pending-manual': null, + archive: null, + ignore: 'DISCOVERY_DOCUMENT_IGNORED', +} as const; + +const getPrimaryPdfDocumentDataId = async (doc: { + title: string; + dataId: string | null; + archivePath: string | null; + artifacts: Array<{ + kind: string; + relativePath: string; + fileName: string; + contentType: string; + }>; +}): Promise => { + if (doc.dataId) { + return doc.dataId; + } + + const pdfArtifact = doc.artifacts.find( + (artifact) => + artifact.kind === 'ATTACHMENT' && + (artifact.contentType === 'application/pdf' || + artifact.fileName.toLowerCase().endsWith('.pdf')), + ); + + if (!doc.archivePath || !pdfArtifact) { + throw new AppError(AppErrorCode.INVALID_BODY, { + message: + 'Dieses Dokument hat noch keine PDF-Datei. Laden Sie zuerst die Mail erneut aus IMAP oder ziehen Sie den Beleg manuell.', + statusCode: 400, + }); + } + + const archiveDir = path.resolve(getAbsoluteArchivePath(doc.archivePath)); + const filePath = path.resolve(archiveDir, pdfArtifact.relativePath); + + if (!filePath.startsWith(`${archiveDir}${path.sep}`)) { + throw new AppError(AppErrorCode.INVALID_BODY, { + message: 'Ungültiger Archivpfad.', + statusCode: 400, + }); + } + + const bytes = await readFile(filePath); + const data = await putNormalizedPdfFileServerSide({ + name: pdfArtifact.fileName || `${doc.title}.pdf`, + type: 'application/pdf', + arrayBuffer: async () => + Promise.resolve(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)), + }); + + return data.id; +}; + +export const discoveryRouter = router({ + /** + * Liste der gefundenen Dokumente für das aktive Team und den aktiven User. + * Reader-Wahl passiert serverseitig anhand der Environment-Konfiguration. + * + * Antwort enthält zusätzlich die Source-Liste des aktuellen Users (pro User + * konfiguriert, nicht pro Team), damit das UI Empty-State-Logik und + * Sync-Status anzeigen kann. + */ + findDocuments: authenticatedProcedure + .input(ZFindDiscoveryDocumentsRequestSchema) + .output(ZFindDiscoveryDocumentsResponseSchema) + .query(async ({ input, ctx }) => { + const configured = isDiscoveryConfigured(); + + const sources = await prisma.source.findMany({ + where: { userId: ctx.user.id, ...(ctx.teamId ? { teamId: ctx.teamId } : {}) }, + orderBy: { createdAt: 'asc' }, + select: { + id: true, + kind: true, + label: true, + lastSyncAt: true, + lastSyncStatus: true, + }, + }); + + const sourceSummaries = sources.map((source) => ({ + id: source.id, + kind: source.kind, + label: source.label, + lastSyncAt: source.lastSyncAt, + lastSyncStatus: source.lastSyncStatus, + })); + + if (!configured) { + return { + documents: [], + total: 0, + nextCursor: null, + configured: false, + hasAnySource: sourceSummaries.length > 0, + sources: sourceSummaries, + }; + } + + const reader = getDiscoveryReader(); + const { teamId, user } = ctx; + const { cursor, ...filter } = input; + + const page = await reader.findDocuments(filter, cursor ?? null, { + teamId: teamId ?? undefined, + userId: user.id, + }); + + return { + documents: page.documents, + total: page.total, + nextCursor: page.nextCursor, + configured: true, + hasAnySource: sourceSummaries.length > 0, + sources: sourceSummaries, + }; + }), + + getDocument: authenticatedProcedure + .input(ZGetDiscoveryDocumentRequestSchema) + .output(ZGetDiscoveryDocumentResponseSchema) + .query(async ({ input, ctx }) => { + if (!isDiscoveryConfigured()) { + return null; + } + const reader = getDiscoveryReader(); + const { teamId, user } = ctx; + return reader.getDocument(input.id, { + teamId: teamId ?? undefined, + userId: user.id, + }); + }), + + /** + * Status-Aktionen auf einem DiscoveryDocument: accept / archive / ignore / + * mark-pending-manual. Auth-Modell: Team-Member darf lokale Uploads ändern, + * eigene IMAP-Belege ändern. Fremde IMAP-Belege bleiben unsichtbar (siehe + * db-reader.buildWhere) und damit auch unveränderbar. + * + * WORM-Regel: ab `acceptedAt != null` (User hat den Beleg als Geschäftsbeleg + * akzeptiert) sind nur noch ACCEPTED → ARCHIVED erlaubt. Reverse zu INBOX + * oder IGNORED ist gesperrt — GoBD-Aufbewahrung. + */ + updateStatus: authenticatedProcedure + .input(ZUpdateDiscoveryDocumentStatusRequestSchema) + .output(ZUpdateDiscoveryDocumentStatusResponseSchema) + .mutation(async ({ input, ctx }) => { + const { teamId, user } = ctx; + if (!teamId) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Aktion braucht einen Team-Kontext.', + }); + } + + const doc = await prisma.discoveryDocument.findFirst({ + where: { + id: input.id, + teamId, + OR: [{ providerSource: 'local' }, { uploadedById: user.id }], + }, + select: { id: true, providerSource: true, status: true, acceptedAt: true }, + }); + if (!doc) { + throw new AppError(AppErrorCode.NOT_FOUND, { + message: 'Dokument nicht gefunden oder nicht änderbar.', + }); + } + + // WORM-Guard: nach Accept nur noch Archivieren erlaubt. + if (doc.acceptedAt && input.action !== 'archive') { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: + 'Dieses Dokument ist als Geschäftsbeleg akzeptiert und unterliegt der ' + + '10-jährigen Aufbewahrung (§ 147 AO / § 257 HGB). Es kann nur noch ' + + 'archiviert, aber nicht zurückgesetzt oder ignoriert werden.', + }); + } + + const newStatus = ACTION_STATUS_MAP[input.action]; + await prisma.$transaction(async (tx) => { + // accept/archive setzen acceptedAt + acceptedById exakt einmal. + // Wichtig für GoBD: Auch ein direkt archivierter Beleg ist damit + // aufbewahrungspflichtig und landet im Exportfluss. + const updateData: { + status: typeof newStatus; + acceptedAt?: Date; + acceptedById?: number; + } = { status: newStatus }; + const startsRetention = + !doc.acceptedAt && (input.action === 'accept' || input.action === 'archive'); + if (startsRetention) { + updateData.acceptedAt = new Date(); + updateData.acceptedById = user.id; + } + + await tx.discoveryDocument.update({ + where: { id: doc.id }, + data: updateData, + }); + + const auditEvent = + startsRetention && input.action === 'archive' + ? 'DISCOVERY_DOCUMENT_ACCEPTED' + : ACTION_AUDIT_MAP[input.action]; + + if (auditEvent) { + await tx.discoveryAuditLog.create({ + data: { + event: auditEvent, + discoveryDocumentId: doc.id, + userId: user.id, + teamId, + metadata: { + action: input.action, + providerSource: doc.providerSource, + retentionStarted: startsRetention, + }, + }, + }); + } + }); + return { ok: true }; + }), + + /** + * Detail-Daten für die Beleg-Detailseite. Liefert Document + alle Artifacts + * (Mail, Body, Anhänge mit sha256), absoluter Server-Pfad fürs FTP-Reingucken, + * Gmail-Deep-Link für IMAP-Belege. + */ + getDocumentDetail: authenticatedProcedure + .input(ZGetDocumentDetailRequestSchema) + .output(ZGetDocumentDetailResponseSchema) + .query(async ({ input, ctx }) => { + const { teamId, user } = ctx; + if (!teamId) return null; + + const doc = await prisma.discoveryDocument.findFirst({ + where: { + id: input.id, + teamId, + OR: [{ providerSource: 'local' }, { uploadedById: user.id }], + }, + include: { + artifacts: { orderBy: { kind: 'asc' } }, + source: { select: { label: true, kind: true } }, + acceptedBy: { select: { name: true } }, + }, + }); + if (!doc) return null; + + const uiStatus = + doc.status === 'INBOX' + ? ('inbox' as const) + : doc.status === 'PENDING_MANUAL' + ? ('pending-manual' as const) + : ('processed' as const); + + // Gmail-Deep-Link: nur für IMAP-Belege mit Gmail-Source und messageId. + // Format: https://mail.google.com/mail/u/0/#search/rfc822msgid: + // Wir haben nur den Hash gespeichert, nicht die Original-messageId — also + // gibt's hier keinen Direkt-Link. Pragmatisch: Search nach Subject. + const gmailDeepLink = + doc.providerSource === 'imap' && doc.source?.kind === 'IMAP' && doc.title + ? `https://mail.google.com/mail/u/0/#search/${encodeURIComponent(doc.title)}` + : null; + + // attachmentCount/hasArchive werden vom Listen-Schema verlangt; in der + // Detail-Antwort spiegeln wir sie aus den realen Artifacts wider. + const attachmentCount = doc.artifacts.filter((a) => a.kind === 'ATTACHMENT').length; + const hasArchive = + doc.archivePath !== null && doc.archivePath !== '' && doc.artifacts.length > 0; + + return { + document: { + id: doc.id, + nativeId: doc.id, + title: doc.title, + correspondent: doc.correspondent, + documentType: doc.documentType, + tags: doc.tags, + documentDate: doc.documentDate, + capturedAt: doc.capturedAt, + status: uiStatus, + bodyText: doc.bodyText, + bodyHasHtml: doc.bodyHasHtml, + archivePath: doc.archivePath, + detectedAmount: doc.detectedAmount, + detectedInvoiceNumber: doc.detectedInvoiceNumber, + portalHint: doc.portalHint, + messageIdHash: doc.messageIdHash, + providerSource: doc.providerSource, + providerNativeId: doc.providerNativeId, + acceptedAt: doc.acceptedAt, + acceptedByName: doc.acceptedBy?.name ?? null, + sourceLabel: doc.source?.label ?? null, + signingEnvelopeId: doc.signingEnvelopeId, + canCreateSigningDocument: + doc.dataId !== null || + doc.artifacts.some( + (a) => + a.kind === 'ATTACHMENT' && + (a.contentType === 'application/pdf' || a.fileName.toLowerCase().endsWith('.pdf')), + ), + attachmentCount, + hasArchive, + }, + artifacts: doc.artifacts.map((a) => ({ + id: a.id, + kind: a.kind, + fileName: a.fileName, + contentType: a.contentType, + fileSize: a.fileSize, + sha256: a.sha256, + relativePath: a.relativePath, + })), + absoluteArchivePath: doc.archivePath ? getAbsoluteArchivePath(doc.archivePath) : null, + gmailDeepLink, + }; + }), + + createSigningDocument: authenticatedProcedure + .input(ZCreateSigningDocumentRequestSchema) + .output(ZCreateSigningDocumentResponseSchema) + .mutation(async ({ input, ctx }) => { + const { teamId, user } = ctx; + if (!teamId) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Signatur-Vorbereitung braucht einen Team-Kontext.', + }); + } + + const doc = await prisma.discoveryDocument.findFirst({ + where: { + id: input.id, + teamId, + OR: [{ providerSource: 'local' }, { uploadedById: user.id }], + }, + include: { + artifacts: true, + signingEnvelope: { select: { id: true } }, + }, + }); + + if (!doc) { + throw new AppError(AppErrorCode.NOT_FOUND, { + message: 'Dokument nicht gefunden oder nicht änderbar.', + }); + } + + if (doc.signingEnvelopeId) { + if (!doc.acceptedAt || doc.status !== 'SIGNED') { + await prisma.$transaction(async (tx) => { + await tx.discoveryDocument.update({ + where: { id: doc.id }, + data: { + status: doc.status === 'ARCHIVED' ? 'ARCHIVED' : 'SIGNED', + acceptedAt: doc.acceptedAt ?? new Date(), + acceptedById: doc.acceptedById ?? user.id, + }, + }); + + if (!doc.acceptedAt) { + await tx.discoveryAuditLog.create({ + data: { + event: 'DISCOVERY_DOCUMENT_ACCEPTED', + discoveryDocumentId: doc.id, + userId: user.id, + teamId, + metadata: { + action: 'create-signing-document', + envelopeId: doc.signingEnvelopeId, + providerSource: doc.providerSource, + retentionStarted: true, + }, + }, + }); + } + }); + } + return { envelopeId: doc.signingEnvelopeId, alreadyExisted: true }; + } + + const documentDataId = await getPrimaryPdfDocumentDataId(doc); + + const envelope = await createEnvelope({ + userId: user.id, + teamId, + internalVersion: 1, + normalizePdf: true, + data: { + type: EnvelopeType.DOCUMENT, + title: doc.title, + envelopeItems: [{ documentDataId }], + }, + meta: { + timezone: 'Europe/Berlin', + distributionMethod: 'NONE', + }, + bypassDefaultRecipients: true, + requestMetadata: ctx.metadata, + }); + + await prisma.$transaction(async (tx) => { + const startsRetention = !doc.acceptedAt; + + await tx.discoveryDocument.update({ + where: { id: doc.id }, + data: { + signingEnvelopeId: envelope.id, + status: doc.status === 'ARCHIVED' ? 'ARCHIVED' : 'SIGNED', + acceptedAt: doc.acceptedAt ?? new Date(), + acceptedById: doc.acceptedById ?? user.id, + }, + }); + + if (startsRetention) { + await tx.discoveryAuditLog.create({ + data: { + event: 'DISCOVERY_DOCUMENT_ACCEPTED', + discoveryDocumentId: doc.id, + userId: user.id, + teamId, + metadata: { + action: 'create-signing-document', + envelopeId: envelope.id, + providerSource: doc.providerSource, + retentionStarted: true, + }, + }, + }); + } + + await tx.discoveryAuditLog.create({ + data: { + event: 'DISCOVERY_SIGNING_DOCUMENT_CREATED', + discoveryDocumentId: doc.id, + userId: user.id, + teamId, + metadata: { + action: 'create-signing-document', + envelopeId: envelope.id, + }, + }, + }); + }); + + return { envelopeId: envelope.id, alreadyExisted: false }; + }), + + /** + * Re-Sync einer einzelnen Mail aus IMAP — laedt Archive nach (eml + body + + * attachments + metadata) fuer Belege, die vor Aktivierung des Archive- + * Features importiert wurden. Idempotent — keine Duplikat-Documents, + * kein Status-Verlust. User-Berechtigungs-Check liegt in resyncSingleDocument(). + */ + resyncSingle: authenticatedProcedure + .input(ZResyncSingleDocumentRequestSchema) + .output(ZResyncSingleDocumentResponseSchema) + .mutation(async ({ input, ctx }) => { + const { teamId, user } = ctx; + if (!teamId) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Re-Sync braucht einen Team-Kontext.', + }); + } + return resyncSingleDocument({ + documentId: input.id, + userId: user.id, + teamId, + }); + }), +}); diff --git a/packages/trpc/server/discovery-router/schema.ts b/packages/trpc/server/discovery-router/schema.ts new file mode 100644 index 0000000..e9e20a8 --- /dev/null +++ b/packages/trpc/server/discovery-router/schema.ts @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { z } from 'zod'; + +export const ZDiscoveryDocumentStatusSchema = z.enum([ + 'inbox', + 'pending-manual', + 'accepted', + 'archived', + 'ignored', + 'processed', +]); + +// Filter-Wert für die Listenansicht. „all" zeigt alle Belege unabhängig vom +// Status — Hauptzweck: Überblick „welche Mail mit welcher Rechnung wann". +// Der DB-Filter ignoriert dann die status-Spalte komplett. +export const ZDiscoveryListFilterSchema = z.union([ + z.literal('all'), + ZDiscoveryDocumentStatusSchema, +]); + +export const ZDiscoveryDocumentSchema = z.object({ + id: z.string(), + nativeId: z.string(), + title: z.string(), + correspondent: z.string().nullable(), + documentType: z.string().nullable(), + tags: z.array(z.string()), + documentDate: z.coerce.date().nullable(), + capturedAt: z.coerce.date(), + status: ZDiscoveryDocumentStatusSchema, + // Optional in Listenansicht (vor allem akzeptierte Belege). + detectedAmount: z.string().nullable().optional(), + detectedInvoiceNumber: z.string().nullable().optional(), + acceptedAt: z.coerce.date().nullable().optional(), + acceptedByName: z.string().nullable().optional(), + // Anzahl ATTACHMENT-Artifacts mit nicht-leerem archivePath. Wenn 0 → Mail + // hat keine herunterladbaren Anhänge (entweder MANUAL ohne PDF, oder vor- + // Archive-Sync-Datensatz). Wird im Listen-Loader vorberechnet. + attachmentCount: z.number().int().nonnegative(), + hasArchive: z.boolean(), + signingEnvelopeId: z.string().nullable().optional(), + canCreateSigningDocument: z.boolean().optional(), +}); + +export const ZSourceKindSchema = z.enum(['IMAP']); + +export const ZSourceSyncStatusSchema = z.enum(['PENDING', 'SUCCESS', 'FAILED', 'SUSPENDED']); + +export const ZSourceSummarySchema = z.object({ + id: z.string(), + kind: ZSourceKindSchema, + label: z.string(), + lastSyncAt: z.coerce.date().nullable(), + lastSyncStatus: ZSourceSyncStatusSchema.nullable(), +}); + +export const ZFindDiscoveryDocumentsRequestSchema = z.object({ + query: z.string().trim().optional(), + // status entweder ein konkreter Status oder "all" für alle. + status: ZDiscoveryListFilterSchema.optional(), + correspondent: z.string().trim().optional(), + documentDateFrom: z.coerce.date().optional(), + documentDateTo: z.coerce.date().optional(), + cursor: z.string().nullable().optional(), +}); + +export const ZFindDiscoveryDocumentsResponseSchema = z.object({ + documents: z.array(ZDiscoveryDocumentSchema), + total: z.number().int().nonnegative(), + nextCursor: z.string().nullable(), + configured: z.boolean(), + hasAnySource: z.boolean(), + sources: z.array(ZSourceSummarySchema), +}); + +export const ZGetDiscoveryDocumentRequestSchema = z.object({ + id: z.string(), +}); + +export const ZGetDiscoveryDocumentResponseSchema = ZDiscoveryDocumentSchema.nullable(); + +export const ZDiscoveryDocumentActionSchema = z.enum([ + 'accept', + 'mark-pending-manual', + 'archive', + 'ignore', +]); + +export const ZUpdateDiscoveryDocumentStatusRequestSchema = z.object({ + id: z.string(), + action: ZDiscoveryDocumentActionSchema, +}); + +export const ZUpdateDiscoveryDocumentStatusResponseSchema = z.object({ + ok: z.boolean(), +}); + +export const ZDiscoveryArtifactKindSchema = z.enum([ + 'MAIL_EML', + 'MAIL_BODY_TEXT', + 'MAIL_BODY_HTML', + 'MAIL_METADATA', + 'ATTACHMENT', +]); + +export const ZDiscoveryArtifactSchema = z.object({ + id: z.string(), + kind: ZDiscoveryArtifactKindSchema, + fileName: z.string(), + contentType: z.string(), + fileSize: z.number().int().nonnegative(), + sha256: z.string().length(64), + relativePath: z.string(), +}); + +export const ZGetDocumentDetailRequestSchema = z.object({ + id: z.string(), +}); + +export const ZGetDocumentDetailResponseSchema = z + .object({ + document: ZDiscoveryDocumentSchema.extend({ + bodyText: z.string().nullable(), + bodyHasHtml: z.boolean(), + archivePath: z.string().nullable(), + detectedAmount: z.string().nullable(), + detectedInvoiceNumber: z.string().nullable(), + portalHint: z.string().nullable(), + messageIdHash: z.string().nullable(), + providerSource: z.string(), + providerNativeId: z.string().nullable(), + acceptedAt: z.coerce.date().nullable(), + acceptedByName: z.string().nullable(), + sourceLabel: z.string().nullable(), + signingEnvelopeId: z.string().nullable(), + canCreateSigningDocument: z.boolean(), + }), + artifacts: z.array(ZDiscoveryArtifactSchema), + /** Absoluter Pfad auf dem Server zum Mail-Ordner (für FTP/SCP-Hinweis). */ + absoluteArchivePath: z.string().nullable(), + /** Deep-Link zur Mail in Gmail, falls messageId vorhanden und Provider Gmail. */ + gmailDeepLink: z.string().nullable(), + }) + .nullable(); + +export type TDiscoveryDocument = z.infer; +export type TSourceSummary = z.infer; +export type TDiscoveryDocumentAction = z.infer; +export type TDiscoveryArtifact = z.infer; +export type TGetDocumentDetailResponse = z.infer; + +export type TFindDiscoveryDocumentsRequest = z.infer; +export type TFindDiscoveryDocumentsResponse = z.infer; +export type TGetDiscoveryDocumentRequest = z.infer; +export type TGetDiscoveryDocumentResponse = z.infer; + +// Re-Sync einer einzelnen Mail aus IMAP — laedt Archive nach fuer Belege, +// die vor Aktivierung des Archive-Features importiert wurden. +export const ZResyncSingleDocumentRequestSchema = z.object({ + id: z.string(), +}); + +export const ZResyncSingleDocumentResponseSchema = z.discriminatedUnion('ok', [ + z.object({ + ok: z.literal(true), + archivePath: z.string(), + attachmentsAdded: z.number().int().nonnegative(), + alreadyHadArchive: z.boolean(), + }), + z.object({ + ok: z.literal(false), + reason: z.string(), + }), +]); + +export type TResyncSingleDocumentRequest = z.infer; +export type TResyncSingleDocumentResponse = z.infer; + +export const ZCreateSigningDocumentRequestSchema = z.object({ + id: z.string(), +}); + +export const ZCreateSigningDocumentResponseSchema = z.object({ + envelopeId: z.string(), + alreadyExisted: z.boolean(), +}); + +export type TCreateSigningDocumentRequest = z.infer; +export type TCreateSigningDocumentResponse = z.infer; diff --git a/packages/trpc/server/intake-router/router.ts b/packages/trpc/server/intake-router/router.ts new file mode 100644 index 0000000..82253e8 --- /dev/null +++ b/packages/trpc/server/intake-router/router.ts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { base64 } from '@scure/base'; + +import { AppError, AppErrorCode } from '@nexasign/lib/errors/app-error'; +import { uploadIntakeDocument } from '@nexasign/lib/server-only/intake'; + +import { authenticatedProcedure, router } from '../trpc'; +import { ZUploadIntakeDocumentRequestSchema, ZUploadIntakeDocumentResponseSchema } from './schema'; + +/** + * Intake-Router — Park-Pfad für manuellen Upload. + * + * In Schritt 1 des Lifecycles („Dokumente finden") gehört kein Upload, weil + * Upload-Aktivität semantisch ein „Erstellen/Ablegen"-Schritt ist. Der + * Mutation-Endpoint ist hier vorbereitet und ans gleiche `DiscoveryDocument`- + * Storage angebunden, sodass Schritt 2 des Lifecycles ihn unverändert + * benutzen kann sobald die UI dafür existiert. + */ +export const intakeRouter = router({ + uploadDocument: authenticatedProcedure + .input(ZUploadIntakeDocumentRequestSchema) + .output(ZUploadIntakeDocumentResponseSchema) + .mutation(async ({ input, ctx }) => { + const { teamId, user } = ctx; + if (!teamId) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Upload braucht einen Team-Kontext.', + }); + } + + const bytes = base64.decode(input.base64); + + const created = await uploadIntakeDocument({ + teamId, + userId: user.id, + fileName: input.fileName, + contentType: input.contentType, + bytes, + }); + + return { + id: created.id, + nativeId: created.id, + title: created.title, + correspondent: created.correspondent, + documentType: created.documentType, + tags: created.tags, + documentDate: created.documentDate, + capturedAt: created.capturedAt, + status: 'inbox' as const, + // Lokal hochgeladene Belege haben ihre Bytes direkt in `DocumentData` + // (nicht im IMAP-Archive). Für die Listen-/UI-Logik zaehlen wir das + // als "ein Anhang verfügbar", auch wenn es kein DiscoveryArtifact-Record + // ist — der Download lauft hier nicht ueber das ZIP-Endpoint. + attachmentCount: 1, + hasArchive: true, + }; + }), +}); diff --git a/packages/trpc/server/intake-router/schema.ts b/packages/trpc/server/intake-router/schema.ts new file mode 100644 index 0000000..a21f8ad --- /dev/null +++ b/packages/trpc/server/intake-router/schema.ts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { z } from 'zod'; + +import { ZDiscoveryDocumentSchema } from '../discovery-router/schema'; + +// Upload: Bytes kommen base64-kodiert vom Client, weil tRPC nativ kein +// Multipart unterstützt. Größenlimit pro Upload: 25 MB. +const MAX_UPLOAD_BYTES = 25 * 1024 * 1024; + +export const ZUploadIntakeDocumentRequestSchema = z.object({ + fileName: z.string().min(1).max(255), + contentType: z.string().min(1).max(127).default('application/pdf'), + base64: z.string().refine( + (s) => { + const approxBytes = (s.length * 3) / 4; + return approxBytes <= MAX_UPLOAD_BYTES; + }, + { message: 'Datei zu groß (max. 25 MB).' }, + ), +}); + +export const ZUploadIntakeDocumentResponseSchema = ZDiscoveryDocumentSchema; + +export type TUploadIntakeDocumentRequest = z.infer; +export type TUploadIntakeDocumentResponse = z.infer; diff --git a/packages/trpc/server/router.ts b/packages/trpc/server/router.ts index b2327f7..76123cc 100644 --- a/packages/trpc/server/router.ts +++ b/packages/trpc/server/router.ts @@ -1,15 +1,18 @@ import { adminRouter } from './admin-router/router'; import { apiTokenRouter } from './api-token-router/router'; import { authRouter } from './auth-router/router'; +import { discoveryRouter } from './discovery-router/router'; import { documentRouter } from './document-router/router'; import { embeddingPresignRouter } from './embedding-router/_router'; import { enterpriseRouter } from './enterprise-router/router'; import { envelopeRouter } from './envelope-router/router'; import { fieldRouter } from './field-router/router'; import { folderRouter } from './folder-router/router'; +import { intakeRouter } from './intake-router/router'; import { organisationRouter } from './organisation-router/router'; import { profileRouter } from './profile-router/router'; import { recipientRouter } from './recipient-router/router'; +import { sourcesRouter } from './sources-router/router'; import { teamRouter } from './team-router/router'; import { templateRouter } from './template-router/router'; import { router } from './trpc'; @@ -20,6 +23,9 @@ export const appRouter = router({ envelope: envelopeRouter, auth: authRouter, profile: profileRouter, + discovery: discoveryRouter, + intake: intakeRouter, + sources: sourcesRouter, document: documentRouter, field: fieldRouter, folder: folderRouter, diff --git a/packages/trpc/server/sources-router/router.ts b/packages/trpc/server/sources-router/router.ts new file mode 100644 index 0000000..3abbc2d --- /dev/null +++ b/packages/trpc/server/sources-router/router.ts @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { Prisma } from '@prisma/client'; + +import { AppError, AppErrorCode } from '@nexasign/lib/errors/app-error'; +import { jobs } from '@nexasign/lib/jobs/client'; +import { + encryptImapConfig, + getDefaultImapHostAllowlist, + isCustomImapHostsAllowed, +} from '@nexasign/lib/server-only/sources/imap'; +import { getSourceAdapter } from '@nexasign/lib/server-only/sources/registry'; +import { prisma } from '@nexasign/prisma'; + +import { authenticatedProcedure, router } from '../trpc'; +import { + ZCancelSyncRunRequestSchema, + ZCancelSyncRunResponseSchema, + ZCreateImapSourceRequestSchema, + ZDeleteSourceRequestSchema, + ZDeleteSourceResponseSchema, + ZListSourcesResponseSchema, + ZListSyncRunsRequestSchema, + ZListSyncRunsResponseSchema, + ZReactivateSourceRequestSchema, + ZReactivateSourceResponseSchema, + ZSourceCapabilitiesResponseSchema, + ZStartSyncRunRequestSchema, + ZStartSyncRunResponseSchema, + ZTestSourceRequestSchema, + ZTestSourceResponseSchema, + ZUpdateImapSourceRequestSchema, +} from './schema'; + +const MAX_IMAP_ACCOUNTS_PER_USER = 3; + +const requireOwnSource = async (sourceId: string, userId: number) => { + const source = await prisma.source.findFirst({ + where: { id: sourceId, userId }, + }); + if (!source) { + throw new AppError(AppErrorCode.NOT_FOUND, { message: 'Quelle nicht gefunden.' }); + } + return source; +}; + +export const sourcesRouter = router({ + getCapabilities: authenticatedProcedure + .output(ZSourceCapabilitiesResponseSchema) + .query(async ({ ctx }) => { + const memberships = await prisma.organisationMember.findMany({ + where: { userId: ctx.user.id }, + select: { + organisation: { + select: { + name: true, + teams: { + orderBy: { createdAt: 'asc' }, + select: { id: true, name: true, url: true }, + }, + }, + }, + }, + }); + + const availableTeams = memberships.flatMap((m) => + m.organisation.teams.map((team) => ({ + id: team.id, + name: team.name, + url: team.url, + organisationName: m.organisation.name, + })), + ); + + return { + imap: { + maxAccountsPerUser: MAX_IMAP_ACCOUNTS_PER_USER, + allowedHosts: [...getDefaultImapHostAllowlist()], + customHostsAllowed: isCustomImapHostsAllowed(), + }, + availableTeams, + }; + }), + + listSources: authenticatedProcedure.output(ZListSourcesResponseSchema).query(async ({ ctx }) => { + const sources = await prisma.source.findMany({ + where: { userId: ctx.user.id }, + orderBy: { createdAt: 'asc' }, + select: { + id: true, + kind: true, + label: true, + teamId: true, + team: { select: { name: true } }, + lastSyncAt: true, + lastSyncStatus: true, + lastSyncError: true, + consecutiveFailures: true, + createdAt: true, + }, + }); + return sources.map(({ team, ...rest }) => ({ + ...rest, + teamName: team.name, + })); + }), + + deleteSource: authenticatedProcedure + .input(ZDeleteSourceRequestSchema) + .output(ZDeleteSourceResponseSchema) + .mutation(async ({ input, ctx }) => { + const source = await requireOwnSource(input.sourceId, ctx.user.id); + + // WORM-Guard: solange noch akzeptierte Belege an dieser Quelle hängen, + // bleibt sie aus GoBD-Gründen unlöschbar — Discovery-Dokumente würden + // sonst per Cascade verschwinden und damit ihre Audit-Spur zerreißen. + const acceptedCount = await prisma.discoveryDocument.count({ + where: { + sourceId: source.id, + acceptedAt: { not: null }, + }, + }); + if (acceptedCount > 0) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: + `An dieser Quelle hängen ${acceptedCount} akzeptierte Belege, die der ` + + `10-jährigen Aufbewahrung unterliegen. Quelle kann erst gelöscht werden, ` + + `nachdem die Belege archiviert oder die Aufbewahrungsfrist abgelaufen ist.`, + }); + } + + await prisma.$transaction([ + prisma.source.delete({ where: { id: source.id } }), + prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_ACCOUNT_DELETED', + sourceId: null, + userId: ctx.user.id, + teamId: ctx.teamId ?? null, + metadata: { kind: source.kind, label: source.label }, + }, + }), + ]); + + return { deleted: true }; + }), + + createImapSource: authenticatedProcedure + .input(ZCreateImapSourceRequestSchema) + .mutation(async ({ input, ctx }) => { + const existing = await prisma.source.count({ + where: { userId: ctx.user.id, kind: 'IMAP' }, + }); + if (existing >= MAX_IMAP_ACCOUNTS_PER_USER) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: `Maximal ${MAX_IMAP_ACCOUNTS_PER_USER} IMAP-Konten pro Nutzer erlaubt.`, + }); + } + + const team = await prisma.team.findFirst({ + where: { + id: input.teamId, + organisation: { members: { some: { userId: ctx.user.id } } }, + }, + select: { id: true }, + }); + if (!team) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Sie sind nicht Mitglied dieses Teams.', + }); + } + + const adapter = getSourceAdapter('IMAP'); + if (!adapter) { + throw new AppError(AppErrorCode.NOT_SETUP, { + message: 'IMAP-Adapter ist nicht initialisiert.', + }); + } + + const test = await adapter.testConnection({ + config: { + host: input.host, + port: input.port, + username: input.username, + password: input.password, + tlsVerify: input.tlsVerify, + }, + }); + if (!test.ok) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: test.error ?? 'Verbindung fehlgeschlagen.', + }); + } + + const encrypted = encryptImapConfig({ + host: input.host, + port: input.port, + username: input.username, + password: input.password, + tlsVerify: input.tlsVerify, + }); + + const created = await prisma.source.create({ + data: { + userId: ctx.user.id, + teamId: team.id, + kind: 'IMAP', + label: input.label, + encryptedConfig: encrypted.ciphertext, + encryptedConfigKeyVersion: encrypted.keyVersion, + }, + select: { + id: true, + kind: true, + label: true, + teamId: true, + team: { select: { name: true } }, + lastSyncAt: true, + lastSyncStatus: true, + lastSyncError: true, + consecutiveFailures: true, + createdAt: true, + }, + }); + + await prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_ACCOUNT_CREATED', + sourceId: created.id, + userId: ctx.user.id, + teamId: team.id, + metadata: { + host: input.host, + port: input.port, + tlsVerify: input.tlsVerify, + label: input.label, + }, + }, + }); + + if (!input.tlsVerify) { + await prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_SYNC_TLS_INSECURE', + sourceId: created.id, + userId: ctx.user.id, + teamId: team.id, + metadata: { context: 'create' }, + }, + }); + } + + // Kein Auto-Sync mehr — User triggert in der Settings-UI mit Zeitraum. + const { team: teamRel, ...rest } = created; + return { ...rest, teamName: teamRel.name }; + }), + + updateImapSource: authenticatedProcedure + .input(ZUpdateImapSourceRequestSchema) + .mutation(async ({ input, ctx }) => { + const source = await requireOwnSource(input.sourceId, ctx.user.id); + + const adapter = getSourceAdapter('IMAP'); + if (!adapter) { + throw new AppError(AppErrorCode.NOT_SETUP, { + message: 'IMAP-Adapter ist nicht initialisiert.', + }); + } + + const password = input.password ?? ''; + let merged: Parameters[0]; + + if (!password) { + const { decryptImapConfig } = await import('@nexasign/lib/server-only/sources/imap'); + const oldConfig = decryptImapConfig({ + ciphertext: source.encryptedConfig, + keyVersion: source.encryptedConfigKeyVersion, + }); + merged = { + host: input.host, + port: input.port, + username: input.username, + password: oldConfig.password, + tlsVerify: input.tlsVerify, + }; + } else { + merged = { + host: input.host, + port: input.port, + username: input.username, + password, + tlsVerify: input.tlsVerify, + }; + } + + const test = await adapter.testConnection({ config: merged }); + if (!test.ok) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: test.error ?? 'Verbindung fehlgeschlagen.', + }); + } + const encrypted = encryptImapConfig(merged); + + await prisma.source.update({ + where: { id: source.id }, + data: { + label: input.label, + encryptedConfig: encrypted.ciphertext, + encryptedConfigKeyVersion: encrypted.keyVersion, + lastSyncStatus: 'PENDING', + lastSyncError: null, + consecutiveFailures: 0, + }, + }); + + await prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_ACCOUNT_UPDATED', + sourceId: source.id, + userId: ctx.user.id, + teamId: ctx.teamId ?? null, + metadata: { passwordChanged: Boolean(input.password) }, + }, + }); + + if (!input.tlsVerify) { + await prisma.discoveryAuditLog.create({ + data: { + event: 'IMAP_SYNC_TLS_INSECURE', + sourceId: source.id, + userId: ctx.user.id, + teamId: ctx.teamId ?? null, + metadata: { context: 'update' }, + }, + }); + } + + return { ok: true }; + }), + + testSource: authenticatedProcedure + .input(ZTestSourceRequestSchema) + .output(ZTestSourceResponseSchema) + .mutation(async ({ input, ctx }) => { + const adapter = getSourceAdapter('IMAP'); + if (!adapter) { + return { ok: false, error: 'IMAP-Adapter ist nicht initialisiert.' }; + } + + if (input.config) { + return adapter.testConnection({ config: input.config }); + } + + if (input.sourceId) { + const source = await requireOwnSource(input.sourceId, ctx.user.id); + const { decryptImapConfig } = await import('@nexasign/lib/server-only/sources/imap'); + const config = decryptImapConfig({ + ciphertext: source.encryptedConfig, + keyVersion: source.encryptedConfigKeyVersion, + }); + return adapter.testConnection({ config }); + } + + return { ok: false, error: 'Weder sourceId noch config übergeben.' }; + }), + + reactivateSource: authenticatedProcedure + .input(ZReactivateSourceRequestSchema) + .output(ZReactivateSourceResponseSchema) + .mutation(async ({ input, ctx }) => { + const source = await requireOwnSource(input.sourceId, ctx.user.id); + + await prisma.source.update({ + where: { id: source.id }, + data: { + lastSyncStatus: 'PENDING', + lastSyncError: null, + consecutiveFailures: 0, + }, + }); + + return { reactivated: true }; + }), + + // ---------------- SyncRun-Endpunkte ---------------- + + startSyncRun: authenticatedProcedure + .input(ZStartSyncRunRequestSchema) + .output(ZStartSyncRunResponseSchema) + .mutation(async ({ input, ctx }) => { + const source = await requireOwnSource(input.sourceId, ctx.user.id); + + if (source.lastSyncStatus === 'SUSPENDED') { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Quelle ist gesperrt. Bitte zuerst reaktivieren.', + }); + } + + // Lock: nur ein laufender SyncRun pro Source. + const active = await prisma.syncRun.findFirst({ + where: { + sourceId: source.id, + status: { in: ['PENDING', 'RUNNING'] }, + }, + select: { id: true }, + }); + if (active) { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Es läuft bereits ein Sync für diese Quelle. Bitte warten oder abbrechen.', + }); + } + + let created; + try { + created = await prisma.syncRun.create({ + data: { + sourceId: source.id, + triggeredById: ctx.user.id, + rangeFrom: input.from, + rangeTo: input.to, + searchTerm: input.searchTerm?.trim() || null, + }, + }); + } catch (err) { + if (err instanceof Prisma.PrismaClientKnownRequestError && err.code === 'P2002') { + throw new AppError(AppErrorCode.UNAUTHORIZED, { + message: 'Es läuft bereits ein Sync für diese Quelle. Bitte warten oder abbrechen.', + }); + } + throw err; + } + + await jobs.triggerJob({ + name: 'internal.run-sync-range', + payload: { syncRunId: created.id }, + }); + + return created; + }), + + listSyncRuns: authenticatedProcedure + .input(ZListSyncRunsRequestSchema) + .output(ZListSyncRunsResponseSchema) + .query(async ({ input, ctx }) => { + // Auth-Check via requireOwnSource (wirft NOT_FOUND wenn fremde Source). + await requireOwnSource(input.sourceId, ctx.user.id); + + return prisma.syncRun.findMany({ + where: { sourceId: input.sourceId }, + orderBy: { startedAt: 'desc' }, + take: input.limit, + }); + }), + + cancelSyncRun: authenticatedProcedure + .input(ZCancelSyncRunRequestSchema) + .output(ZCancelSyncRunResponseSchema) + .mutation(async ({ input, ctx }) => { + const syncRun = await prisma.syncRun.findUnique({ + where: { id: input.syncRunId }, + include: { source: { select: { userId: true } } }, + }); + if (!syncRun || syncRun.source.userId !== ctx.user.id) { + throw new AppError(AppErrorCode.NOT_FOUND, { message: 'Sync-Lauf nicht gefunden.' }); + } + if (syncRun.status !== 'PENDING' && syncRun.status !== 'RUNNING') { + return { cancelRequested: false }; + } + await prisma.syncRun.update({ + where: { id: syncRun.id }, + data: { cancelRequested: true }, + }); + return { cancelRequested: true }; + }), +}); diff --git a/packages/trpc/server/sources-router/schema.ts b/packages/trpc/server/sources-router/schema.ts new file mode 100644 index 0000000..48ca068 --- /dev/null +++ b/packages/trpc/server/sources-router/schema.ts @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// © 2026 NexaStack, NexaSign contributors +import { z } from 'zod'; + +import { ZSourceKindSchema, ZSourceSyncStatusSchema } from '../discovery-router/schema'; + +export const ZSourceListItemSchema = z.object({ + id: z.string(), + kind: ZSourceKindSchema, + label: z.string(), + teamId: z.number().int().positive(), + teamName: z.string(), + lastSyncAt: z.coerce.date().nullable(), + lastSyncStatus: ZSourceSyncStatusSchema, + lastSyncError: z.string().nullable(), + consecutiveFailures: z.number().int().nonnegative(), + createdAt: z.coerce.date(), +}); + +export const ZListSourcesResponseSchema = z.array(ZSourceListItemSchema); + +export const ZDeleteSourceRequestSchema = z.object({ + sourceId: z.string(), +}); + +export const ZDeleteSourceResponseSchema = z.object({ + deleted: z.boolean(), +}); + +export const ZImapConnectionConfigSchema = z.object({ + host: z.string().min(1).max(255), + port: z.number().int().min(1).max(65535).default(993), + username: z.string().min(1).max(255), + password: z.string().min(1).max(1024), + tlsVerify: z.boolean().default(true), +}); + +export const ZCreateImapSourceRequestSchema = ZImapConnectionConfigSchema.extend({ + teamId: z.number().int().positive(), + label: z.string().min(1).max(120), +}); + +export const ZUpdateImapSourceRequestSchema = ZCreateImapSourceRequestSchema.extend({ + sourceId: z.string(), + password: z.string().min(1).max(1024).optional(), +}); + +export const ZTestSourceRequestSchema = z.object({ + sourceId: z.string().optional(), + config: ZImapConnectionConfigSchema.optional(), +}); + +export const ZTestSourceResponseSchema = z.object({ + ok: z.boolean(), + error: z.string().optional(), +}); + +export const ZReactivateSourceRequestSchema = z.object({ + sourceId: z.string(), +}); + +export const ZReactivateSourceResponseSchema = z.object({ + reactivated: z.boolean(), +}); + +// SyncRun-Modell — User triggert pro Lauf einen expliziten Zeitraum. +export const ZSyncRunStatusSchema = z.enum([ + 'PENDING', + 'RUNNING', + 'SUCCESS', + 'FAILED', + 'CANCELLED', +]); + +export const ZSyncRunSchema = z.object({ + id: z.string(), + sourceId: z.string(), + rangeFrom: z.coerce.date(), + rangeTo: z.coerce.date(), + searchTerm: z.string().nullable(), + status: ZSyncRunStatusSchema, + mailsChecked: z.number().int().nonnegative(), + documentsAuto: z.number().int().nonnegative(), + documentsManual: z.number().int().nonnegative(), + documentsIgnored: z.number().int().nonnegative(), + documentsFailed: z.number().int().nonnegative(), + errorMessage: z.string().nullable(), + cancelRequested: z.boolean(), + startedAt: z.coerce.date(), + finishedAt: z.coerce.date().nullable(), +}); + +export const ZStartSyncRunRequestSchema = z + .object({ + sourceId: z.string(), + from: z.coerce.date(), + to: z.coerce.date(), + searchTerm: z.string().trim().min(1).max(120).optional(), + }) + .refine((data) => data.from < data.to, { + message: '„Von"-Datum muss vor „Bis"-Datum liegen.', + path: ['from'], + }); + +export const ZStartSyncRunResponseSchema = ZSyncRunSchema; + +export const ZListSyncRunsRequestSchema = z.object({ + sourceId: z.string(), + limit: z.number().int().min(1).max(50).default(10), +}); + +export const ZListSyncRunsResponseSchema = z.array(ZSyncRunSchema); + +export const ZCancelSyncRunRequestSchema = z.object({ + syncRunId: z.string(), +}); + +export const ZCancelSyncRunResponseSchema = z.object({ + cancelRequested: z.boolean(), +}); + +export const ZSourceCapabilitiesResponseSchema = z.object({ + imap: z.object({ + maxAccountsPerUser: z.number().int().positive(), + allowedHosts: z.array(z.string()), + customHostsAllowed: z.boolean(), + }), + availableTeams: z.array( + z.object({ + id: z.number().int().positive(), + name: z.string(), + url: z.string(), + organisationName: z.string(), + }), + ), +}); + +export type TSourceListItem = z.infer; +export type TListSourcesResponse = z.infer; +export type TDeleteSourceRequest = z.infer; +export type TCreateImapSourceRequest = z.infer; +export type TUpdateImapSourceRequest = z.infer; +export type TTestSourceRequest = z.infer; +export type TTestSourceResponse = z.infer; +export type TReactivateSourceRequest = z.infer; + +export type TSyncRun = z.infer; +export type TSyncRunStatus = z.infer; +export type TStartSyncRunRequest = z.infer; +export type TListSyncRunsRequest = z.infer; +export type TCancelSyncRunRequest = z.infer; diff --git a/scripts/nexasign/deploy-nginx-config.sh b/scripts/nexasign/deploy-nginx-config.sh new file mode 100644 index 0000000..5085ffc --- /dev/null +++ b/scripts/nexasign/deploy-nginx-config.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# NexaSign — Deploy der nginx-Config aus dem Repo nach /etc/nginx/sites-enabled. +# +# Source-of-truth ist deploy/nginx/nexasign.nexastack.co.conf im Repo. +# Live-Pfad ist /etc/nginx/sites-enabled/nexasign.nexastack.co. Dieses Skript +# kopiert den Repo-Stand auf den Live-Pfad (mit Backup), prueft die Syntax und +# reloadet nginx — atomar, mit Rollback bei Fehler. +# +# Aufruf: sudo bash scripts/nexasign/deploy-nginx-config.sh + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SOURCE="${REPO_ROOT}/deploy/nginx/nexasign.nexastack.co.conf" +TARGET="/etc/nginx/sites-enabled/nexasign.nexastack.co" + +if [[ "$(id -u)" -ne 0 ]]; then + echo "FEHLER: Skript muss als root laufen (sudo)." >&2 + exit 1 +fi + +if [[ ! -f "${SOURCE}" ]]; then + echo "FEHLER: Repo-Source fehlt: ${SOURCE}" >&2 + exit 1 +fi + +if [[ ! -f "${TARGET}" ]]; then + echo "FEHLER: Live-Target existiert nicht (erst-Setup haendisch?): ${TARGET}" >&2 + exit 1 +fi + +# Diff anzeigen, falls vorhanden +if ! diff -q "${TARGET}" "${SOURCE}" >/dev/null 2>&1; then + echo "Diff zwischen live und repo:" + diff -u "${TARGET}" "${SOURCE}" || true + echo +fi + +# Backup mit Zeitstempel — NICHT in sites-enabled/ legen, weil nginx sonst die +# Backup-Datei mitlaedt und z. B. doppelte `listen :443`-Direktiven zu einem +# emerg-Fehler fuehren. Backups landen unter /var/backups/nginx/. +BACKUP_DIR="/var/backups/nginx" +mkdir -p "${BACKUP_DIR}" +chmod 700 "${BACKUP_DIR}" +BACKUP="${BACKUP_DIR}/$(basename "${TARGET}").bak.$(date +%s)" +cp -p "${TARGET}" "${BACKUP}" +echo "Backup erstellt: ${BACKUP}" + +# Atomar via Move auf gleichem FS +TEMP="${TARGET}.new" +cp -p "${SOURCE}" "${TEMP}" +mv "${TEMP}" "${TARGET}" +echo "Deployed: ${SOURCE} → ${TARGET}" + +# Vor Syntax-Check: alte Stray-Backups aus sites-enabled/ wegraeumen, sonst +# laedt nginx sie mit und erkennt z. B. doppelte listen-Direktiven. +STRAY_BACKUPS=$(find "$(dirname "${TARGET}")" -maxdepth 1 -type f -name "$(basename "${TARGET}").bak.*" 2>/dev/null || true) +if [[ -n "${STRAY_BACKUPS}" ]]; then + echo "Verschiebe Alt-Backups aus sites-enabled/ nach ${BACKUP_DIR}:" + while IFS= read -r f; do + [[ -z "$f" ]] && continue + mv "$f" "${BACKUP_DIR}/$(basename "$f")" + echo " $f → ${BACKUP_DIR}/$(basename "$f")" + done <<< "${STRAY_BACKUPS}" +fi + +# Syntax pruefen — bei Fehler Rollback +if ! nginx -t 2>&1; then + echo "FEHLER: nginx -t schlug fehl. Rollback…" >&2 + cp "${BACKUP}" "${TARGET}" + nginx -t >&2 || true + exit 1 +fi + +# Reload (kein restart) — bestehende Verbindungen bleiben erhalten +systemctl reload nginx +echo "nginx reloaded." diff --git a/scripts/nexasign/release-gate.sh b/scripts/nexasign/release-gate.sh index e596364..730cc60 100755 --- a/scripts/nexasign/release-gate.sh +++ b/scripts/nexasign/release-gate.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# NexaSign V1 release gate. +# NexaFile V1 release gate. # # Runs the checks that must stay green before tagging a release candidate: # generated Prisma client, focused TypeScript checks, lint, production build, @@ -83,6 +83,44 @@ run() { "$@" } +run_v1_checks() { + printf '\n== V1 NexaFile checks ==\n' + + bash -n tools/nexasign-gobd-export.sh + bash -n tools/nexasign-retention-check.sh + + local legacy_hits + legacy_hits=$( + grep -RIn "NexaSign\\|NexaFILE\\|alle 15 Minuten" \ + apps/remix/app \ + packages/email \ + apps/docs/src \ + README.md \ + docker/README.md \ + ARCHITECTURE.md \ + CONTRIBUTING.md \ + --exclude-dir=node_modules \ + --exclude-dir=build \ + --exclude-dir=.turbo \ + 2>/dev/null \ + | grep -v "contributors" \ + | grep -v "github.com" \ + | grep -v "X-NexaSign-Secret" \ + || true + ) + + if [[ -n "${legacy_hits}" ]]; then + echo "FEHLER: User-facing Legacy-Branding oder falsche Sync-Kopie gefunden:" >&2 + echo "${legacy_hits}" >&2 + exit 1 + fi + + if [[ ! -f packages/prisma/migrations/20260430130000_backfill_discovery_retention_start/migration.sql ]]; then + echo "FEHLER: Discovery-Retention-Backfill-Migration fehlt." >&2 + exit 1 + fi +} + prepare_e2e_environment() { printf '\n== prepare E2E environment ==\n' @@ -100,9 +138,10 @@ prepare_e2e_environment() { export NEXT_PRIVATE_SMTP_PORT="${NEXT_PRIVATE_SMTP_PORT:-2500}" export NEXT_PRIVATE_SMTP_USERNAME="${NEXT_PRIVATE_SMTP_USERNAME:-nexasign}" export NEXT_PRIVATE_SMTP_PASSWORD="${NEXT_PRIVATE_SMTP_PASSWORD:-password}" - export NEXT_PRIVATE_SMTP_FROM_NAME="${NEXT_PRIVATE_SMTP_FROM_NAME:-NexaSign}" + export NEXT_PRIVATE_SMTP_FROM_NAME="${NEXT_PRIVATE_SMTP_FROM_NAME:-NexaFile}" export NEXT_PRIVATE_SMTP_FROM_ADDRESS="${NEXT_PRIVATE_SMTP_FROM_ADDRESS:-noreply@nexastack.co}" export NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH="${NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH:-${REPO_ROOT}/apps/remix/example/cert.p12}" + export NEXT_PRIVATE_SIGNING_PASSPHRASE="${NEXT_PRIVATE_SIGNING_PASSPHRASE:-}" export CI="${CI:-1}" if command -v docker >/dev/null 2>&1; then @@ -125,7 +164,7 @@ DEFAULT_E2E_TEST_PATH="e2e/release/signing-preflight.spec.ts e2e/envelopes/envel export NEXT_PRIVATE_SIGNING_TRANSPORT="${NEXT_PRIVATE_SIGNING_TRANSPORT:-local}" -echo "NexaSign V1 Release Gate" +echo "NexaFile V1 Release Gate" echo "Repo: ${REPO_ROOT}" echo "E2E mode: ${E2E_MODE}" echo @@ -134,6 +173,7 @@ run npm run prisma:generate run npx tsc -p packages/lib/tsconfig.json --noEmit run npx tsc -p apps/remix/tsconfig.json --noEmit run npx tsc -p packages/app-tests/tsconfig.json --noEmit +run_v1_checks if [[ "${RUN_LINT}" -eq 1 ]]; then run npx turbo run lint --concurrency=1 @@ -162,4 +202,4 @@ if [[ "${RUN_DRIFT}" -eq 1 ]]; then fi echo -echo "PASS NexaSign V1 release gate completed." +echo "PASS NexaFile V1 release gate completed." diff --git a/scripts/nexasign/sync-public-statics.sh b/scripts/nexasign/sync-public-statics.sh new file mode 100755 index 0000000..c9b3714 --- /dev/null +++ b/scripts/nexasign/sync-public-statics.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# NexaSign — Sync der statischen Public-Assets in den nginx-Static-Pfad. +# +# Hintergrund: Der nginx-Server-Block fuer nexasign.nexastack.co liefert +# /logo-(1x|2x).(png|webp) NICHT aus dem Remix-Container, sondern direkt aus +# /var/www/nexasign/ (statisch, ohne proxy_pass) — damit dieselben Logos auch +# fuer die PHP-/vorlagen/-Seiten verfuegbar sind, ohne den Container-Build zu +# beruehren. Damit /var/www/nexasign/ nach jedem Source-Update nicht aus dem +# Repo driftet, gibt es genau dieses Skript. +# +# Idempotent. Kopiert byte-genau aus apps/remix/public/. Eigentumsrechte +# folgen der nginx-Worker-Konvention (www-data:www-data, 0644). +# +# Aufruf vom Repo-Root: +# sudo bash scripts/nexasign/sync-public-statics.sh + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +SOURCE_DIR="${REPO_ROOT}/apps/remix/public" +TARGET_DIR="${NEXASIGN_NGINX_STATIC_DIR:-/var/www/nexasign}" + +if [[ ! -d "${SOURCE_DIR}" ]]; then + echo "FEHLER: Source-Verzeichnis fehlt: ${SOURCE_DIR}" >&2 + exit 1 +fi + +if [[ ! -d "${TARGET_DIR}" ]]; then + echo "FEHLER: Ziel-Verzeichnis fehlt: ${TARGET_DIR}" >&2 + echo "Hinweis: nginx-Server-Block muss /var/www/nexasign/ als root fuer" >&2 + echo " /logo-*.{png,webp} eingetragen haben." >&2 + exit 1 +fi + +if [[ "$(id -u)" -ne 0 ]]; then + echo "FEHLER: Skript muss als root laufen (sudo)." >&2 + exit 1 +fi + +echo "Sync ${SOURCE_DIR}/ → ${TARGET_DIR}/" +echo + +# Logos sind die einzigen Files, die nginx aus diesem Pfad ausliefert. +# Favicons gehen ueber proxy_pass an die App und liegen NICHT in /var/www/. +ASSETS=( + logo-1x.png + logo-1x.webp + logo-2x.png + logo-2x.webp +) + +for f in "${ASSETS[@]}"; do + src="${SOURCE_DIR}/${f}" + dst="${TARGET_DIR}/${f}" + + if [[ ! -f "${src}" ]]; then + echo " SKIP ${f} (im Repo nicht vorhanden)" + continue + fi + + install -o www-data -g www-data -m 0644 "${src}" "${dst}" + size="$(stat -c %s "${dst}")" + printf " WROTE %-20s %s bytes\n" "${f}" "${size}" +done + +echo +echo "Done. nginx serviert ab sofort die neuen Logos aus ${TARGET_DIR}/." diff --git a/templates/vorlagen-index/_nav.php b/templates/vorlagen-index/_nav.php index bcdf1fc..f4cc50e 100644 --- a/templates/vorlagen-index/_nav.php +++ b/templates/vorlagen-index/_nav.php @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // © 2026 NexaStack, NexaSign contributors. Based on NexaSign (AGPL-3.0). /** - * Gemeinsamer Header/Nav für alle NexaSign-Vorlagen-Seiten. + * Gemeinsamer Header/Nav für alle NexaFILE-/Vorlagen-Seiten. * Layout-gleich zur Remix-App (app-header.tsx + app-nav-desktop.tsx): Logo, * Nav-Links, Search-Button, Inbox-Icon, Avatar-Slot. Auf den PHP-Seiten gibt es * keinen Login-State — Search/Inbox/Avatar sind daher reine Portal-Links in @@ -90,7 +90,12 @@ function nx_active(string $needle, string $haystack): string { text-decoration: none; } @media (min-width: 768px) { .nx-logo { display: inline-flex; } } /* md:inline-flex */ - .nx-logo img { height: 60px; width: auto; display: block; } + /* Hoehe identisch zur Remix-AppHeader (apps/remix/app/components/general/app-header.tsx), + damit die Logo-Groesse zwischen PHP-Vorlagen-Seiten und der Remix-App nicht springt. + 80px gewählt, weil ein 120px-hohes Logo (502px breit bei 4.18:1 Aspect) zusammen mit + den 4 Nav-Links + Search-Button + Inbox + Avatar-Block die max-w-screen-xl (1280px) + Header-Breite sprengt — Logo würde optisch in den Nav-Bereich gequetscht. */ + .nx-logo img { height: 80px; width: auto; display: block; } /* ─────── Mittelblock: Nav + Search (=AppNavDesktop) ─────── */ .nx-nav-wrapper { @@ -103,11 +108,13 @@ function nx_active(string $needle, string $haystack): string { } @media (min-width: 768px) { .nx-nav-wrapper { display: flex; } } - .nx-primary-nav { + .nx-primary-nav, + .nx-mobile-primary-nav { display: flex; align-items: baseline; gap: 1.5rem; /* gap-x-6 */ } - .nx-primary-nav a { + .nx-primary-nav a, + .nx-mobile-primary-nav a { color: var(--nx-muted-foreground); text-decoration: none; font-weight: 500; /* font-medium */ @@ -115,8 +122,23 @@ function nx_active(string $needle, string $haystack): string { border-radius: 0.375rem; /* rounded-md */ transition: opacity 0.15s; } - .nx-primary-nav a:hover { opacity: 0.8; } - .nx-primary-nav a.nx-nav-active { color: var(--nx-foreground); } + .nx-primary-nav a:hover, + .nx-mobile-primary-nav a:hover { opacity: 0.8; } + .nx-primary-nav a.nx-nav-active, + .nx-mobile-primary-nav a.nx-nav-active { color: var(--nx-foreground); } + + .nx-mobile-primary-nav { + width: 100%; + padding: 0.75rem 1rem 0; + overflow-x: auto; + border-top: 1px solid var(--nx-border); + background: rgba(253, 249, 243, 0.95); + } + .nx-mobile-primary-nav a { + white-space: nowrap; + font-size: 0.9375rem; + } + @media (min-width: 768px) { .nx-mobile-primary-nav { display: none; } } /* ─────── Search-Button (Portal-Link ins App-Command-Menu) ─────── */ .nx-search-btn { @@ -161,21 +183,56 @@ function nx_active(string $needle, string $haystack): string { .nx-inbox-btn:hover { color: var(--nx-foreground); } .nx-inbox-btn svg { width: 1.25rem; height: 1.25rem; } - /* ─────── Avatar-Platz: „Zur App"-Button ─────── */ + /* ─────── Avatar-Platz: „Zur App"-Button ───────────────────────────────── + Visuelles Pendant zur MenuSwitcher-Komponente in Remix + (apps/remix/app/components/general/menu-switcher.tsx): h-12, ohne Border, + Avatar-Kreis links + Text-Block (auf md+) + Chevron-Icon rechts. + PHP hat keinen Server-Session-Kontext, daher kein User-Name — wir zeigen + stattdessen das NS-Monogramm und „Zur App" als Sekundärtext. */ .nx-app-btn { margin-left: 1rem; /* md:ml-4 */ - display: flex; align-items: center; - height: 2.5rem; padding: 0 1rem; - border: 1px solid var(--nx-border); - border-radius: 0.5rem; - background: var(--nx-background); + display: flex; align-items: center; gap: 0.5rem; + height: 3rem; /* h-12 */ + padding: 0.5rem 0.5rem; /* py-2 md:px-2 */ + background: transparent; color: var(--nx-foreground); - font-size: 0.875rem; font-weight: 500; text-decoration: none; flex-shrink: 0; - transition: background 0.15s; + border: 0; + transition: opacity 0.15s; + } + .nx-app-btn:hover { opacity: 0.85; } + .nx-app-avatar { + display: flex; align-items: center; justify-content: center; + flex-shrink: 0; + height: 2.25rem; width: 2.25rem; /* h-9 w-9 — wie AvatarWithText */ + border-radius: 9999px; /* rounded-full */ + background: var(--nx-primary); + color: var(--nx-primary-foreground); + font-family: var(--nx-font-serif, 'Newsreader', Georgia, serif); + font-size: 0.875rem; font-weight: 600; + letter-spacing: -0.01em; + } + .nx-app-text { + display: none; /* default hidden */ + flex-direction: column; align-items: flex-start; + line-height: 1.1; gap: 0.125rem; + } + @media (min-width: 1024px) { .nx-app-text { display: flex; } } /* lg:flex */ + .nx-app-text-primary { + font-size: 0.875rem; font-weight: 600; /* AvatarWithText primary */ + color: var(--nx-foreground); + } + .nx-app-text-secondary { + font-size: 0.75rem; font-weight: 400; + color: var(--nx-muted-foreground); + } + .nx-app-chevron { + margin-left: auto; + flex-shrink: 0; + height: 1rem; width: 1rem; + color: var(--nx-muted-foreground); } - .nx-app-btn:hover { background: var(--nx-muted); }
@@ -185,16 +242,17 @@ function nx_active(string $needle, string $haystack): string { NexaSign + alt="NexaSign" width="335" height="80">
@@ -221,8 +279,29 @@ function nx_active(string $needle, string $haystack): string { - - Zur App + + + + + Zur App + NexaSign + + + +
+ diff --git a/tools/nexasign-gobd-export.sh b/tools/nexasign-gobd-export.sh index 85292a1..da79bcb 100755 --- a/tools/nexasign-gobd-export.sh +++ b/tools/nexasign-gobd-export.sh @@ -2,14 +2,16 @@ # SPDX-License-Identifier: AGPL-3.0-or-later # © 2026 NexaStack, NexaSign contributors. Based on NexaSign (AGPL-3.0). # -# nexasign-gobd-export — Exportiert signierte Dokumente + Audit-Log + PDF-Binaries -# als ZIP-Paket mit SHA-256-Manifest für GoBD-Betriebsprüfung +# nexasign-gobd-export — Exportiert signierte Dokumente, gefundene Belege, +# Audit-Logs und PDF-/Mail-Artefakte als ZIP-Paket +# mit SHA-256-Manifest für GoBD-Betriebsprüfung # (§ 147 Abs. 6 AO, Z2/Z3). # -# Phase 2 (Stand 2026-04-21): -# - Envelope-Metadaten (CSV) -# - DocumentAuditLog (CSV) +# V1 (Stand 2026-04-30): +# - Envelope-Metadaten + DocumentAuditLog (CSV) +# - DiscoveryDocument-Metadaten + DiscoveryAuditLog (CSV) # - PDF-Binaries pro Envelope (documents//_.pdf) +# - Mail-/Anhang-Artefakte pro gefundenem Beleg (discovery/<documentId>/...) # - SHA-256-Manifest (manifest.sha256) # - README.md mit rechtlichem Kontext # @@ -20,6 +22,11 @@ # Nutzung: sudo bash nexasign-gobd-export.sh <VON> <BIS> <ZIEL-DIR> # z. B.: sudo bash nexasign-gobd-export.sh 2026-01-01 2026-12-31 /tmp/gobd-2026 # +# Optional: +# NEXASIGN_DISCOVERY_ARCHIVE_PATH=/var/lib/nexasign-archive +# Host-Pfad des Discovery-Archivs. Im Container ist das normalerweise +# /var/lib/nexasign/sources, auf dem Host /var/lib/nexasign-archive. +# set -euo pipefail VON="${1:-}" @@ -32,11 +39,27 @@ if [[ -z "$VON" || -z "$BIS" || -z "$ZIEL" ]]; then exit 1 fi +if [[ ! "$VON" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ || ! "$BIS" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then + echo "FEHLER: VON/BIS müssen im Format YYYY-MM-DD angegeben werden." >&2 + exit 2 +fi + +if ! date -d "$VON" >/dev/null 2>&1 || ! date -d "$BIS" >/dev/null 2>&1; then + echo "FEHLER: VON/BIS enthalten kein gültiges Datum." >&2 + exit 2 +fi + +if [[ "$VON" > "$BIS" ]]; then + echo "FEHLER: VON darf nicht nach BIS liegen." >&2 + exit 2 +fi + DB_CONTAINER="nexasign-db" DB_USER="nexasign" DB_NAME="nexasign" +DISCOVERY_ARCHIVE_BASE="${NEXASIGN_DISCOVERY_ARCHIVE_PATH:-/var/lib/nexasign-archive}" -mkdir -p "$ZIEL/documents" +mkdir -p "$ZIEL/documents" "$ZIEL/discovery" echo "[$(date -Iseconds)] Export startet: $VON bis $BIS → $ZIEL" # Helper: psql im Container mit tab-separated, ohne Header/Footer, nur die Daten @@ -75,7 +98,122 @@ N_AUDIT=$(( $(wc -l < "$ZIEL/audit-log.csv") - 1 )) echo " → audit-log.csv ($N_AUDIT Events)" # ───────────────────────────────────────────────────────────────── -# 3. PDF-Binaries pro Envelope +# 3. Gefundene/akzeptierte Belege +# acceptedAt ist der GoBD-Retention-Start fuer DiscoveryDocument. +# ───────────────────────────────────────────────────────────────── +docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" \ + -c "COPY ( + SELECT id, title, correspondent, status, \"providerSource\", \"providerNativeId\", + \"documentDate\", \"capturedAt\", \"acceptedAt\", \"acceptedById\", \"sourceId\", + \"detectedAmount\", \"detectedInvoiceNumber\", \"archivePath\", \"signingEnvelopeId\" + FROM \"DiscoveryDocument\" + WHERE \"acceptedAt\" IS NOT NULL + AND \"acceptedAt\" BETWEEN '$VON' AND '$BIS 23:59:59' + ORDER BY \"acceptedAt\", \"capturedAt\" + ) TO STDOUT WITH CSV HEADER" \ + > "$ZIEL/discovery-documents.csv" +N_DISCOVERY=$(( $(wc -l < "$ZIEL/discovery-documents.csv") - 1 )) +echo " → discovery-documents.csv ($N_DISCOVERY akzeptierte Belege)" + +docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" \ + -c "COPY ( + SELECT id, event, \"sourceId\", \"discoveryDocumentId\", \"userId\", \"teamId\", + metadata, \"createdAt\" + FROM \"DiscoveryAuditLog\" + WHERE \"createdAt\" BETWEEN '$VON' AND '$BIS 23:59:59' + ORDER BY \"discoveryDocumentId\", \"createdAt\" + ) TO STDOUT WITH CSV HEADER" \ + > "$ZIEL/discovery-audit-log.csv" +N_DISCOVERY_AUDIT=$(( $(wc -l < "$ZIEL/discovery-audit-log.csv") - 1 )) +echo " → discovery-audit-log.csv ($N_DISCOVERY_AUDIT Events)" + +docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" \ + -c "COPY ( + SELECT d.id, d.title, d.status, d.\"providerSource\", d.\"providerNativeId\", + d.\"acceptedAt\", d.\"archivePath\", COUNT(a.id) AS \"artifactCount\", + CASE + WHEN d.\"archivePath\" IS NULL OR d.\"archivePath\" = '' THEN 'NO_ARCHIVE_PATH' + WHEN COUNT(a.id) = 0 THEN 'NO_ARTIFACT_ROWS' + ELSE 'OK' + END AS reason + FROM \"DiscoveryDocument\" d + LEFT JOIN \"DiscoveryArtifact\" a ON a.\"discoveryDocumentId\" = d.id + WHERE d.\"acceptedAt\" IS NOT NULL + AND d.\"acceptedAt\" BETWEEN '$VON' AND '$BIS 23:59:59' + GROUP BY d.id + HAVING d.\"archivePath\" IS NULL OR d.\"archivePath\" = '' OR COUNT(a.id) = 0 + ORDER BY d.\"acceptedAt\", d.\"capturedAt\" + ) TO STDOUT WITH CSV HEADER" \ + > "$ZIEL/discovery-missing-artifacts.csv" +N_DISCOVERY_MISSING=$(( $(wc -l < "$ZIEL/discovery-missing-artifacts.csv") - 1 )) +echo " → discovery-missing-artifacts.csv ($N_DISCOVERY_MISSING Belege ohne Mail-Artefakte)" + +# ───────────────────────────────────────────────────────────────── +# 4. Mail-/Anhang-Artefakte pro akzeptiertem Beleg +# ───────────────────────────────────────────────────────────────── +N_DISCOVERY_FILES=0 +N_DISCOVERY_SKIPPED=0 +ARTIFACTS_TSV=$(psql_raw -c " + SELECT d.id, d.\"archivePath\", a.kind, a.\"fileName\", a.\"relativePath\", a.sha256 + FROM \"DiscoveryDocument\" d + JOIN \"DiscoveryArtifact\" a ON a.\"discoveryDocumentId\" = d.id + WHERE d.\"acceptedAt\" IS NOT NULL + AND d.\"acceptedAt\" BETWEEN '$VON' AND '$BIS 23:59:59' + ORDER BY d.id, a.\"createdAt\" +") + +while IFS=$'\t' read -r DOC_ID ARCHIVE_PATH ART_KIND FILE_NAME REL_PATH EXPECTED_SHA; do + [[ -z "$DOC_ID" ]] && continue + + if [[ -z "$ARCHIVE_PATH" || -z "$REL_PATH" ]]; then + echo " ⚠ Discovery-Artefakt ohne Pfad übersprungen: doc=$DOC_ID kind=$ART_KIND file=$FILE_NAME" + N_DISCOVERY_SKIPPED=$((N_DISCOVERY_SKIPPED + 1)) + continue + fi + + case "$ARCHIVE_PATH" in + /*|*..* ) + echo " ⚠ Unsicherer archivePath übersprungen: doc=$DOC_ID path=$ARCHIVE_PATH" + N_DISCOVERY_SKIPPED=$((N_DISCOVERY_SKIPPED + 1)) + continue + ;; + esac + + case "$REL_PATH" in + /*|*..* ) + echo " ⚠ Unsicherer relativePath übersprungen: doc=$DOC_ID path=$REL_PATH" + N_DISCOVERY_SKIPPED=$((N_DISCOVERY_SKIPPED + 1)) + continue + ;; + esac + + SRC="$DISCOVERY_ARCHIVE_BASE/$ARCHIVE_PATH/$REL_PATH" + DEST="$ZIEL/discovery/$DOC_ID/$REL_PATH" + + if [[ ! -f "$SRC" ]]; then + echo " ⚠ Discovery-Artefakt nicht gefunden: $SRC" + N_DISCOVERY_SKIPPED=$((N_DISCOVERY_SKIPPED + 1)) + continue + fi + + mkdir -p "$(dirname "$DEST")" + cp -p "$SRC" "$DEST" + + ACTUAL_SHA=$(sha256sum "$DEST" | awk '{print $1}') + if [[ -n "$EXPECTED_SHA" && "$ACTUAL_SHA" != "$EXPECTED_SHA" ]]; then + echo " ⚠ Hash-Abweichung bei $DEST (DB=$EXPECTED_SHA, Datei=$ACTUAL_SHA)" + rm -f "$DEST" + N_DISCOVERY_SKIPPED=$((N_DISCOVERY_SKIPPED + 1)) + continue + fi + + N_DISCOVERY_FILES=$((N_DISCOVERY_FILES + 1)) +done <<< "$ARTIFACTS_TSV" + +echo " → discovery/ ($N_DISCOVERY_FILES Mail-/Anhang-Dateien exportiert, $N_DISCOVERY_SKIPPED übersprungen)" + +# ───────────────────────────────────────────────────────────────── +# 5. PDF-Binaries pro Envelope # Jedes EnvelopeItem verweist auf DocumentData.data (Base64-kodiertes PDF). # ───────────────────────────────────────────────────────────────── N_PDF=0 @@ -119,32 +257,24 @@ done <<< "$ITEMS_TSV" echo " → documents/ ($N_PDF PDF-Dateien exportiert)" # ───────────────────────────────────────────────────────────────── -# 4. SHA-256-Manifest über alle Dateien (außer manifest selbst + ZIP) -# ───────────────────────────────────────────────────────────────── -( - cd "$ZIEL" - find . -type f ! -name 'manifest.sha256' ! -name '*.zip' -print0 \ - | xargs -0 sha256sum \ - | sort -k2 \ - > manifest.sha256 -) -echo " → manifest.sha256 ($(wc -l < "$ZIEL/manifest.sha256") Einträge)" - -# ───────────────────────────────────────────────────────────────── -# 5. README.md +# 6. README.md # ───────────────────────────────────────────────────────────────── cat > "$ZIEL/README.md" <<EOF -# NexaSign GoBD-Export +# NexaFile GoBD-Export **Zeitraum:** $VON bis $BIS **Erzeugt:** $(date -Iseconds) -**Tool:** \`nexasign-gobd-export\` (Phase 2, 2026-04) +**Tool:** \`nexasign-gobd-export\` (V1, 2026-04) ## Paket-Inhalt - \`envelopes.csv\` — Metadaten der im Zeitraum abgeschlossen signierten Envelopes ($N_ENV Stück) -- \`audit-log.csv\` — Vollständiger Audit-Trail im Zeitraum ($N_AUDIT Events) +- \`audit-log.csv\` — Audit-Trail der Signatur-Dokumente im Zeitraum ($N_AUDIT Events) +- \`discovery-documents.csv\` — akzeptierte gefundene Belege im Zeitraum, nach \`acceptedAt\` ($N_DISCOVERY Stück) +- \`discovery-audit-log.csv\` — Audit-Trail der Quellen-/Belegsuche im Zeitraum ($N_DISCOVERY_AUDIT Events) +- \`discovery-missing-artifacts.csv\` — akzeptierte Belege ohne exportierbare Mail-/Anhang-Artefakte ($N_DISCOVERY_MISSING Stück) - \`documents/<envelope-id>/<order>_<title>.pdf\` — PDF-Binaries aller signierten Dokumente ($N_PDF Dateien) +- \`discovery/<discovery-document-id>/...\` — gespeicherte E-Mails, Body-Dateien, Metadaten und Anhänge ($N_DISCOVERY_FILES Dateien) - \`manifest.sha256\` — SHA-256-Hashes aller enthaltenen Dateien (Integritätsnachweis) - \`README.md\` — diese Datei @@ -170,13 +300,32 @@ Versionen aus der \`DocumentData.data\`-Spalte — also mit eingebetteten Signat und Fields. Die Original-Uploads (\`initialData\`) werden in diesem Paket nicht separat exportiert. +Gefundene Belege aus „Dokumente finden" werden aufgenommen, sobald sie in NexaFile +akzeptiert wurden (\`acceptedAt\`). Die zugehörigen Mail-/Anhang-Dateien werden aus +\`$DISCOVERY_ARCHIVE_BASE\` kopiert. Falls Dateien im Export fehlen, prüfen Sie den +Server-Pfad, die Warnungen in der Konsolen-Ausgabe dieses Exports und +\`discovery-missing-artifacts.csv\`. Altimporte ohne Archive können in der App per +„Erneut aus IMAP laden" nachgefüttert werden. + --- -NexaSign / NexaStack · AGPL-3.0 · Keine Rechtsberatung. +NexaFile / NexaStack · AGPL-3.0 · Keine Rechtsberatung. EOF # ───────────────────────────────────────────────────────────────── -# 6. ZIP +# 7. SHA-256-Manifest über alle Dateien (außer manifest selbst + ZIP) +# ───────────────────────────────────────────────────────────────── +( + cd "$ZIEL" + find . -type f ! -name 'manifest.sha256' ! -name '*.zip' -print0 \ + | xargs -0 sha256sum \ + | sort -k2 \ + > manifest.sha256 +) +echo " → manifest.sha256 ($(wc -l < "$ZIEL/manifest.sha256") Einträge)" + +# ───────────────────────────────────────────────────────────────── +# 8. ZIP # ───────────────────────────────────────────────────────────────── ZIPNAME="nexasign-gobd-export_${VON}_${BIS}.zip" (cd "$ZIEL" && zip -q -r "$ZIPNAME" . -x "$ZIPNAME") diff --git a/tools/nexasign-retention-check.sh b/tools/nexasign-retention-check.sh index 457bba0..fc20232 100755 --- a/tools/nexasign-retention-check.sh +++ b/tools/nexasign-retention-check.sh @@ -3,11 +3,12 @@ # © 2026 NexaStack, NexaSign contributors. Based on NexaSign (AGPL-3.0). # # nexasign-retention-check — Prüft Aufbewahrungs-Fristen signierter Envelopes -# gemäß § 147 AO / § 257 HGB (10 Jahre GoBD). +# und akzeptierter gefundener Belege gemäß +# § 147 AO / § 257 HGB (10 Jahre GoBD). # # Funktion: -# - Liste aller COMPLETED-Envelopes -# - Alter seit completedAt +# - Liste aller COMPLETED-Envelopes und akzeptierten DiscoveryDocuments +# - Alter seit completedAt bzw. acceptedAt # - Kategorisierung: OK / BALD-ABLAUFEND (9-10 Jahre) / ABGELAUFEN (>10 Jahre) # - Bericht in /var/log/nexasign/retention-check.log # @@ -25,7 +26,7 @@ DB_NAME="nexasign" LOG_DIR="/var/log/nexasign" LOG_FILE="$LOG_DIR/retention-check.log" RETENTION_YEARS=10 -WARN_YEARS=9 # Envelopes ab diesem Alter werden als "bald ablaufend" gemeldet +WARN_YEARS=9 # Belege ab diesem Alter werden als "bald ablaufend" gemeldet mkdir -p "$LOG_DIR" exec >>"$LOG_FILE" 2>&1 @@ -33,8 +34,38 @@ exec >>"$LOG_FILE" 2>&1 echo "────────────────────────────────────────────────" echo "[$(date -Iseconds)] Retention-Check gestartet" +check_result() { + local KIND="$1" + local DATE_LABEL="$2" + local RESULT="$3" + + while IFS=$'\t' read -r ID TITLE REFERENCE_DATE DAYS; do + [[ -z "$ID" ]] && continue + TOTAL=$((TOTAL + 1)) + YEARS=$(( DAYS / 365 )) + DAYS_LEFT=$(( RETENTION_YEARS * 365 - DAYS )) + + if [[ "$YEARS" -ge "$RETENTION_YEARS" ]]; then + EXPIRED=$((EXPIRED + 1)) + echo " [ABGELAUFEN] $KIND $ID — '$TITLE' — $DATE_LABEL=$REFERENCE_DATE — Alter=${YEARS}J" + elif [[ "$YEARS" -ge "$WARN_YEARS" ]]; then + WARNING=$((WARNING + 1)) + echo " [WARNUNG] $KIND $ID — '$TITLE' — $DATE_LABEL=$REFERENCE_DATE — Alter=${YEARS}J (läuft in ${DAYS_LEFT:-?} Tagen ab)" + else + OK=$((OK + 1)) + fi + done <<< "$RESULT" +} + +TOTAL=0 +EXPIRED=0 +WARNING=0 +OK=0 +TOTAL_ENVELOPES=0 +TOTAL_DISCOVERY=0 + # Alle COMPLETED-Envelopes mit Alter abrufen -RESULT=$(docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -At -F $'\t' --pset=footer=off -c " +ENVELOPE_RESULT=$(docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -At -F $'\t' --pset=footer=off -c " SELECT id, title, @@ -45,31 +76,28 @@ RESULT=$(docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -At -F $'\ AND \"completedAt\" IS NOT NULL ORDER BY \"completedAt\" ") +TOTAL_ENVELOPES=$(printf '%s\n' "$ENVELOPE_RESULT" | sed '/^$/d' | wc -l) +check_result "Envelope" "completedAt" "$ENVELOPE_RESULT" -TOTAL=0 -EXPIRED=0 -WARNING=0 -OK=0 - -while IFS=$'\t' read -r ID TITLE COMPLETED DAYS; do - [[ -z "$ID" ]] && continue - TOTAL=$((TOTAL + 1)) - YEARS=$(( DAYS / 365 )) - DAYS_LEFT=$(( RETENTION_YEARS * 365 - DAYS )) - - if [[ "$YEARS" -ge "$RETENTION_YEARS" ]]; then - EXPIRED=$((EXPIRED + 1)) - echo " [ABGELAUFEN] $ID — '$TITLE' — completedAt=$COMPLETED — Alter=${YEARS}J" - elif [[ "$YEARS" -ge "$WARN_YEARS" ]]; then - WARNING=$((WARNING + 1)) - echo " [WARNUNG] $ID — '$TITLE' — completedAt=$COMPLETED — Alter=${YEARS}J (läuft in ${DAYS_LEFT:-?} Tagen ab)" - else - OK=$((OK + 1)) - fi -done <<< "$RESULT" +# Alle akzeptierten DiscoveryDocuments mit Alter abrufen. +# acceptedAt ist der GoBD-Retention-Start; status kann danach ACCEPTED/SIGNED/ARCHIVED sein. +DISCOVERY_RESULT=$(docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -At -F $'\t' --pset=footer=off -c " + SELECT + id, + title, + \"acceptedAt\"::date, + EXTRACT(DAY FROM (NOW() - \"acceptedAt\")) AS days_old + FROM \"DiscoveryDocument\" + WHERE \"acceptedAt\" IS NOT NULL + ORDER BY \"acceptedAt\" +") +TOTAL_DISCOVERY=$(printf '%s\n' "$DISCOVERY_RESULT" | sed '/^$/d' | wc -l) +check_result "DiscoveryDocument" "acceptedAt" "$DISCOVERY_RESULT" echo "Zusammenfassung:" -echo " Gesamt: $TOTAL COMPLETED-Envelopes" +echo " Gesamt: $TOTAL aufbewahrungspflichtige Belege" +echo " Envelopes: $TOTAL_ENVELOPES COMPLETED" +echo " Gefunden: $TOTAL_DISCOVERY akzeptiert" echo " OK (<${WARN_YEARS}J): $OK" echo " Bald ablaufend: $WARNING (zwischen ${WARN_YEARS}J und ${RETENTION_YEARS}J)" echo " Abgelaufen: $EXPIRED (≥${RETENTION_YEARS}J — Admin kann endgültig archivieren)" diff --git a/turbo.json b/turbo.json index 1479ba0..b554d74 100644 --- a/turbo.json +++ b/turbo.json @@ -144,6 +144,13 @@ "NEXT_PRIVATE_OIDC_PROMPT", "NEXT_PRIVATE_WEBHOOK_SSRF_BYPASS_HOSTS", "NEXT_PUBLIC_TURNSTILE_SITE_KEY", - "NEXT_PRIVATE_TURNSTILE_SECRET_KEY" + "NEXT_PRIVATE_TURNSTILE_SECRET_KEY", + "NEXT_PRIVATE_DISCOVERY_TRANSPORT", + "NEXT_PRIVATE_DISCOVERY_PAPERLESS_URL", + "NEXT_PRIVATE_DISCOVERY_PAPERLESS_TOKEN", + "NEXT_PRIVATE_IMAP_CREDENTIAL_KEY", + "NEXT_PRIVATE_IMAP_ALLOW_CUSTOM_HOSTS", + "NEXT_PRIVATE_IMAP_HOST_ALLOWLIST", + "NEXT_PRIVATE_DISCOVERY_ARCHIVE_PATH" ] }