fix(migrations): merge main and rechain compliance migration as 031 after 030_add_mobile_devices
Merge main branch into compliance templates feature branch. Main had advanced with migrations 027-030 (ensure_shared_links, audit_logs, user_language_preference, mobile_devices) since this branch forked. Our compliance migration was 027 with down_revision 026, which conflicted with main's 027_ensure_shared_links_table. Changes: - Merge main (including i18n, audit logs, mobile, GraphQL features) - Resolve conflicts in app/api/__init__.py, app/models.py, tests/conftest.py - Rename 027_add_compliance_templates → 031_add_compliance_templates - Rechain: down_revision 026_add_scheduled_jobs → 030_add_mobile_devices - Add ComplianceTemplate to migrations/env.py imports - Alembic now has single head: 031_add_compliance_templates
This commit is contained in:
@@ -97,6 +97,22 @@ MAX_UPLOAD_SIZE=1073741824
|
||||
# Allowed request headers (use * to allow all)
|
||||
# CORS_ALLOWED_HEADERS=*
|
||||
|
||||
# **Audit Logging & SIEM Integration** (see docs/ConfigurationGuide.md#audit-logging)
|
||||
# Enable HTTP request audit logging middleware
|
||||
AUDIT_LOGGING_ENABLED=true
|
||||
# Include client IP in audit log entries (disable for GDPR-sensitive deployments)
|
||||
AUDIT_LOG_INCLUDE_CLIENT_IP=true
|
||||
|
||||
# Forward audit events to an external SIEM system (Syslog, Splunk, Logstash, Grafana, etc.)
|
||||
# AUDIT_SIEM_ENABLED=false
|
||||
# AUDIT_SIEM_TRANSPORT=syslog # syslog | http
|
||||
# AUDIT_SIEM_SYSLOG_HOST=localhost
|
||||
# AUDIT_SIEM_SYSLOG_PORT=514
|
||||
# AUDIT_SIEM_SYSLOG_PROTOCOL=udp # udp | tcp
|
||||
# AUDIT_SIEM_HTTP_URL= # e.g. https://splunk:8088/services/collector/event
|
||||
# AUDIT_SIEM_HTTP_TOKEN= # Bearer / HEC token
|
||||
# AUDIT_SIEM_HTTP_CUSTOM_HEADERS= # Comma-separated Key:Value pairs
|
||||
|
||||
# **Rate Limiting** (see SECURITY_AUDIT.md and docs/API.md)
|
||||
# Protects against DoS attacks and API abuse by limiting request rates per IP/user
|
||||
# Enabled by default - highly recommended for production
|
||||
@@ -511,3 +527,12 @@ EMBEDDING_MAX_TOKENS=8000
|
||||
# Attach PII (IP addresses, user agents) to Sentry events.
|
||||
# Disable (default) to stay GDPR/CCPA compliant.
|
||||
# SENTRY_SEND_DEFAULT_PII=false
|
||||
|
||||
# **Mobile App – Push Notifications**
|
||||
# Push notifications are delivered via Expo's push notification service
|
||||
# (https://expo.dev/notifications) which routes to APNs (iOS) and FCM (Android).
|
||||
# No additional credentials are required on the server side.
|
||||
# The mobile app registers its Expo push token via POST /api/mobile/register-device.
|
||||
#
|
||||
# To use native FCM/APNs directly (without Expo relay), replace the
|
||||
# send_expo_push_notification function in app/utils/push_notification.py.
|
||||
|
||||
@@ -17,6 +17,7 @@ concurrency:
|
||||
|
||||
env:
|
||||
IMAGE_NAME: christianlouis/docuelevate
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
jobs:
|
||||
# ══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -8,6 +8,9 @@ on:
|
||||
schedule:
|
||||
- cron: '37 1 * * 1'
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
|
||||
@@ -12,6 +12,9 @@ permissions:
|
||||
pull-requests: write
|
||||
packages: write
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Semantic Release
|
||||
|
||||
@@ -16,6 +16,9 @@ permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
|
||||
jobs:
|
||||
ruff-auto-fix:
|
||||
name: Auto-fix Ruff Issues
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2026-03-09T23:00:57Z
|
||||
2026-03-11T23:43:28Z
|
||||
|
||||
+110
@@ -10,6 +10,116 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
<!-- version list -->
|
||||
|
||||
## v0.118.0 (2026-03-11)
|
||||
|
||||
### Features
|
||||
|
||||
- **api**: Add GraphQL endpoint at /graphql with Strawberry
|
||||
([`a41ded5`](https://github.com/christianlouis/DocuElevate/commit/a41ded535f32d4892199208e1cab54cc189fde13))
|
||||
|
||||
|
||||
## v0.117.1 (2026-03-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Resolve all 47 failing tests in main
|
||||
([`df4c91a`](https://github.com/christianlouis/DocuElevate/commit/df4c91a58661e2ecf9fda15500e4ba1259674168))
|
||||
|
||||
|
||||
## v0.117.0 (2026-03-11)
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
- Opt into Node.js 24 for all GitHub Actions workflows
|
||||
([`c306d80`](https://github.com/christianlouis/DocuElevate/commit/c306d80755193e4b12222c73ed4da442a2d5e23c))
|
||||
|
||||
### Documentation
|
||||
|
||||
- **changelog**: Update changelog [skip ci]
|
||||
([`ab19ae5`](https://github.com/christianlouis/DocuElevate/commit/ab19ae57060ff2be8e9172714c5e3b308c45334d))
|
||||
|
||||
- **changelog**: Update changelog [skip ci]
|
||||
([`c5b67fe`](https://github.com/christianlouis/DocuElevate/commit/c5b67fe36464b0756553cc54614d0f77273772ec))
|
||||
|
||||
- **changelog**: Update changelog [skip ci]
|
||||
([`eb22a58`](https://github.com/christianlouis/DocuElevate/commit/eb22a580651b4de477b3b5cc945581776a6775fa))
|
||||
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
- Opt into Node.js 24 for all GitHub Actions workflows
|
||||
([`c306d80`](https://github.com/christianlouis/DocuElevate/commit/c306d80755193e4b12222c73ed4da442a2d5e23c))
|
||||
|
||||
### Documentation
|
||||
|
||||
- **changelog**: Update changelog [skip ci]
|
||||
([`c5b67fe`](https://github.com/christianlouis/DocuElevate/commit/c5b67fe36464b0756553cc54614d0f77273772ec))
|
||||
|
||||
- **changelog**: Update changelog [skip ci]
|
||||
([`eb22a58`](https://github.com/christianlouis/DocuElevate/commit/eb22a580651b4de477b3b5cc945581776a6775fa))
|
||||
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
- Opt into Node.js 24 for all GitHub Actions workflows
|
||||
([`c306d80`](https://github.com/christianlouis/DocuElevate/commit/c306d80755193e4b12222c73ed4da442a2d5e23c))
|
||||
|
||||
### Documentation
|
||||
|
||||
- **changelog**: Update changelog [skip ci]
|
||||
([`eb22a58`](https://github.com/christianlouis/DocuElevate/commit/eb22a580651b4de477b3b5cc945581776a6775fa))
|
||||
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
- Opt into Node.js 24 for all GitHub Actions workflows
|
||||
([`c306d80`](https://github.com/christianlouis/DocuElevate/commit/c306d80755193e4b12222c73ed4da442a2d5e23c))
|
||||
|
||||
|
||||
## v0.116.0 (2026-03-11)
|
||||
|
||||
### Documentation
|
||||
|
||||
- **changelog**: Update changelog [skip ci]
|
||||
([`d6fb787`](https://github.com/christianlouis/DocuElevate/commit/d6fb78715ae550f25a925bdc629eb2945f455009))
|
||||
|
||||
### Testing
|
||||
|
||||
- **views**: Add comprehensive coverage tests for 11 view modules
|
||||
([`c8987d9`](https://github.com/christianlouis/DocuElevate/commit/c8987d966bd949634d222a7809ec52c3ed258f81))
|
||||
|
||||
- **views**: Boost coverage for 11 view modules toward 100%
|
||||
([`6fb1df1`](https://github.com/christianlouis/DocuElevate/commit/6fb1df1aade8a8c98c27fe50dbe44045cba1724d))
|
||||
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Testing
|
||||
|
||||
- **views**: Add comprehensive coverage tests for 11 view modules
|
||||
([`c8987d9`](https://github.com/christianlouis/DocuElevate/commit/c8987d966bd949634d222a7809ec52c3ed258f81))
|
||||
|
||||
- **views**: Boost coverage for 11 view modules toward 100%
|
||||
([`6fb1df1`](https://github.com/christianlouis/DocuElevate/commit/6fb1df1aade8a8c98c27fe50dbe44045cba1724d))
|
||||
|
||||
|
||||
## v0.115.0 (2026-03-10)
|
||||
|
||||
|
||||
## v0.114.1 (2026-03-10)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **db**: Add migration to create shared_links table for databases that skipped 025
|
||||
([`289dcc3`](https://github.com/christianlouis/DocuElevate/commit/289dcc375c111c8d71bd04ef31f184a0e6a3f6f2))
|
||||
|
||||
|
||||
## v0.114.0 (2026-03-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
DocuElevate Build Information
|
||||
==============================
|
||||
Version: 0.114.0
|
||||
Build Date: 2026-03-09T23:00:57Z
|
||||
Git Commit: 5fd3f0661b8d86ba6b3f92481675d820aec0d53c
|
||||
Git Short SHA: 5fd3f06
|
||||
Version: 0.118.0
|
||||
Build Date: 2026-03-11T23:43:28Z
|
||||
Git Commit: 39db5fc564af339724d2297748172290208966e0
|
||||
Git Short SHA: 39db5fc
|
||||
Git Branch: main
|
||||
Commit Date: 2026-03-10T00:00:39+01:00
|
||||
Build Timestamp: 2026-03-09T23:00:57Z
|
||||
Commit Date: 2026-03-12T00:43:10+01:00
|
||||
Build Timestamp: 2026-03-11T23:43:28Z
|
||||
==============================
|
||||
|
||||
@@ -8,6 +8,7 @@ from fastapi import APIRouter
|
||||
|
||||
from app.api.admin_users import router as admin_users_router
|
||||
from app.api.api_tokens import router as api_tokens_router
|
||||
from app.api.audit_logs import router as audit_logs_router
|
||||
from app.api.azure import router as azure_router
|
||||
from app.api.backup import router as backup_router
|
||||
from app.api.billing import router as billing_router
|
||||
@@ -18,9 +19,11 @@ from app.api.dropbox import router as dropbox_router
|
||||
from app.api.duplicates import router as duplicates_router
|
||||
from app.api.files import router as files_router
|
||||
from app.api.google_drive import router as google_drive_router
|
||||
from app.api.i18n import router as i18n_router
|
||||
from app.api.imap_accounts import router as imap_accounts_router
|
||||
from app.api.integrations import router as integrations_router
|
||||
from app.api.logs import router as logs_router
|
||||
from app.api.mobile import router as mobile_router
|
||||
from app.api.notifications import router as notifications_router
|
||||
from app.api.onboarding import router as onboarding_router
|
||||
from app.api.onedrive import router as onedrive_router
|
||||
@@ -83,4 +86,7 @@ router.include_router(imap_accounts_router)
|
||||
router.include_router(integrations_router)
|
||||
router.include_router(notifications_router)
|
||||
router.include_router(scheduled_jobs_router)
|
||||
router.include_router(audit_logs_router)
|
||||
router.include_router(i18n_router)
|
||||
router.include_router(mobile_router)
|
||||
router.include_router(compliance_router)
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
Audit log REST API endpoints.
|
||||
|
||||
Provides read-only access to the comprehensive audit log for admin users.
|
||||
Events are append-only — there are no update or delete endpoints.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, Request
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.auth import require_login
|
||||
from app.database import get_db
|
||||
from app.utils.audit_service import count_events, query_events
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/audit-logs")
|
||||
@require_login
|
||||
async def list_audit_logs(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
action: str | None = Query(None, description="Filter by action (exact match)"),
|
||||
user: str | None = Query(None, description="Filter by username"),
|
||||
resource_type: str | None = Query(None, description="Filter by resource type"),
|
||||
severity: str | None = Query(None, description="Filter by severity level"),
|
||||
since: datetime | None = Query(None, description="Only events at or after this ISO-8601 timestamp"),
|
||||
until: datetime | None = Query(None, description="Only events at or before this ISO-8601 timestamp"),
|
||||
limit: int = Query(50, ge=1, le=500, description="Max rows to return"),
|
||||
offset: int = Query(0, ge=0, description="Rows to skip for pagination"),
|
||||
) -> dict[str, Any]:
|
||||
"""Return audit log entries with optional filtering and pagination.
|
||||
|
||||
Requires authentication. Returns events in reverse chronological order.
|
||||
"""
|
||||
entries = query_events(
|
||||
db,
|
||||
action=action,
|
||||
user=user,
|
||||
resource_type=resource_type,
|
||||
severity=severity,
|
||||
since=since,
|
||||
until=until,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
)
|
||||
total = count_events(
|
||||
db,
|
||||
action=action,
|
||||
user=user,
|
||||
resource_type=resource_type,
|
||||
severity=severity,
|
||||
since=since,
|
||||
until=until,
|
||||
)
|
||||
return {
|
||||
"items": [_serialize(e) for e in entries],
|
||||
"total": total,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/audit-logs/actions")
|
||||
@require_login
|
||||
async def list_distinct_actions(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
) -> list[str]:
|
||||
"""Return the distinct action values present in the audit log."""
|
||||
from app.models import AuditLog
|
||||
|
||||
rows = db.query(AuditLog.action).distinct().order_by(AuditLog.action).all()
|
||||
return [r[0] for r in rows]
|
||||
|
||||
|
||||
@router.get("/audit-logs/users")
|
||||
@require_login
|
||||
async def list_distinct_users(
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
) -> list[str]:
|
||||
"""Return the distinct user values present in the audit log."""
|
||||
from app.models import AuditLog
|
||||
|
||||
rows = db.query(AuditLog.user).distinct().order_by(AuditLog.user).all()
|
||||
return [r[0] for r in rows]
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
|
||||
def _serialize(entry) -> dict[str, Any]:
|
||||
"""Convert an AuditLog row to a JSON-safe dict."""
|
||||
import json as _json
|
||||
|
||||
return {
|
||||
"id": entry.id,
|
||||
"timestamp": entry.timestamp.isoformat() if entry.timestamp else None,
|
||||
"user": entry.user,
|
||||
"action": entry.action,
|
||||
"resource_type": entry.resource_type,
|
||||
"resource_id": entry.resource_id,
|
||||
"ip_address": entry.ip_address,
|
||||
"details": _json.loads(entry.details) if entry.details else None,
|
||||
"severity": entry.severity,
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
"""
|
||||
GraphQL API endpoint for DocuElevate.
|
||||
|
||||
Provides a flexible query interface alongside the existing REST API.
|
||||
Schema covers: documents, pipelines, settings, and users.
|
||||
|
||||
Endpoint: /graphql
|
||||
GraphiQL playground: /graphql (via browser)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Annotated, Any
|
||||
|
||||
import strawberry
|
||||
from fastapi import Depends, Request
|
||||
from sqlalchemy.orm import Session
|
||||
from strawberry.fastapi import GraphQLRouter
|
||||
|
||||
from app.auth import get_current_user
|
||||
from app.config import settings
|
||||
from app.database import get_db
|
||||
from app.models import ApplicationSettings, FileRecord, Pipeline, PipelineStep, UserProfile
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Strawberry types
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class DocumentType:
|
||||
"""A processed document stored in the system."""
|
||||
|
||||
id: int
|
||||
owner_id: str | None
|
||||
original_filename: str | None
|
||||
local_filename: str
|
||||
file_size: int
|
||||
mime_type: str | None
|
||||
document_title: str | None
|
||||
is_duplicate: bool
|
||||
ocr_quality_score: int | None
|
||||
pipeline_id: int | None
|
||||
created_at: datetime | None
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class PipelineStepType:
|
||||
"""A single step within a processing pipeline."""
|
||||
|
||||
id: int
|
||||
pipeline_id: int
|
||||
position: int
|
||||
step_type: str
|
||||
label: str | None
|
||||
enabled: bool
|
||||
created_at: datetime | None
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class PipelineType:
|
||||
"""A processing pipeline with its ordered steps."""
|
||||
|
||||
id: int
|
||||
owner_id: str | None
|
||||
name: str
|
||||
description: str | None
|
||||
is_default: bool
|
||||
is_active: bool
|
||||
steps: list[PipelineStepType]
|
||||
created_at: datetime | None
|
||||
updated_at: datetime | None
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class SettingType:
|
||||
"""An application configuration setting stored in the database."""
|
||||
|
||||
id: int
|
||||
key: str
|
||||
value: str | None
|
||||
created_at: datetime | None
|
||||
updated_at: datetime | None
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class UserType:
|
||||
"""A user profile in the system."""
|
||||
|
||||
id: int
|
||||
user_id: str
|
||||
display_name: str | None
|
||||
is_blocked: bool
|
||||
subscription_tier: str | None
|
||||
onboarding_completed: bool
|
||||
created_at: datetime | None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Conversion helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _document_from_record(rec: FileRecord) -> DocumentType:
|
||||
return DocumentType(
|
||||
id=rec.id,
|
||||
owner_id=rec.owner_id,
|
||||
original_filename=rec.original_filename,
|
||||
local_filename=rec.local_filename,
|
||||
file_size=rec.file_size,
|
||||
mime_type=rec.mime_type,
|
||||
document_title=rec.document_title,
|
||||
is_duplicate=rec.is_duplicate,
|
||||
ocr_quality_score=rec.ocr_quality_score,
|
||||
pipeline_id=rec.pipeline_id,
|
||||
created_at=rec.created_at,
|
||||
)
|
||||
|
||||
|
||||
def _pipeline_step_from_record(step: PipelineStep) -> PipelineStepType:
|
||||
return PipelineStepType(
|
||||
id=step.id,
|
||||
pipeline_id=step.pipeline_id,
|
||||
position=step.position,
|
||||
step_type=step.step_type,
|
||||
label=step.label,
|
||||
enabled=step.enabled,
|
||||
created_at=step.created_at,
|
||||
)
|
||||
|
||||
|
||||
def _pipeline_from_record(pipeline: Pipeline, db: Session) -> PipelineType:
|
||||
steps = db.query(PipelineStep).filter(PipelineStep.pipeline_id == pipeline.id).order_by(PipelineStep.position).all()
|
||||
return PipelineType(
|
||||
id=pipeline.id,
|
||||
owner_id=pipeline.owner_id,
|
||||
name=pipeline.name,
|
||||
description=pipeline.description,
|
||||
is_default=pipeline.is_default,
|
||||
is_active=pipeline.is_active,
|
||||
steps=[_pipeline_step_from_record(s) for s in steps],
|
||||
created_at=pipeline.created_at,
|
||||
updated_at=pipeline.updated_at,
|
||||
)
|
||||
|
||||
|
||||
def _setting_from_record(setting: ApplicationSettings) -> SettingType:
|
||||
return SettingType(
|
||||
id=setting.id,
|
||||
key=setting.key,
|
||||
value=setting.value,
|
||||
created_at=setting.created_at,
|
||||
updated_at=setting.updated_at,
|
||||
)
|
||||
|
||||
|
||||
def _user_from_profile(profile: UserProfile) -> UserType:
|
||||
return UserType(
|
||||
id=profile.id,
|
||||
user_id=profile.user_id,
|
||||
display_name=profile.display_name,
|
||||
is_blocked=profile.is_blocked,
|
||||
subscription_tier=profile.subscription_tier,
|
||||
onboarding_completed=profile.onboarding_completed,
|
||||
created_at=profile.created_at,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Context helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Keys that contain sensitive data and must never be returned via GraphQL
|
||||
_SENSITIVE_SETTING_KEYS: frozenset[str] = frozenset(
|
||||
{
|
||||
"openai_api_key",
|
||||
"azure_ai_key",
|
||||
"session_secret",
|
||||
"database_url",
|
||||
"redis_url",
|
||||
"dropbox_app_secret",
|
||||
"dropbox_refresh_token",
|
||||
"google_drive_credentials_json",
|
||||
"onedrive_client_secret",
|
||||
"onedrive_refresh_token",
|
||||
"smtp_password",
|
||||
"nextcloud_password",
|
||||
"s3_secret_access_key",
|
||||
"ftp_password",
|
||||
"sftp_password",
|
||||
"webdav_password",
|
||||
"stripe_secret_key",
|
||||
"stripe_webhook_secret",
|
||||
"sentry_dsn",
|
||||
"social_auth_google_client_secret",
|
||||
"social_auth_microsoft_client_secret",
|
||||
"social_auth_apple_private_key",
|
||||
"social_auth_dropbox_app_secret",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _get_current_user_id(user: dict[str, Any] | None) -> str | None:
|
||||
"""Extract the stable user identifier from the user dict."""
|
||||
if not user:
|
||||
return None
|
||||
return user.get("preferred_username") or user.get("email") or user.get("id") or None
|
||||
|
||||
|
||||
def _get_db_and_user(info: strawberry.types.Info) -> tuple[Session, dict[str, Any] | None]:
|
||||
"""Extract the database session and current user from the Strawberry context."""
|
||||
db: Session = info.context["db"]
|
||||
user: dict[str, Any] | None = info.context.get("user")
|
||||
return db, user
|
||||
|
||||
|
||||
def _require_auth(user: dict[str, Any] | None) -> None:
|
||||
"""Raise an error when authentication is enabled and no valid user is present."""
|
||||
if settings.auth_enabled and not user:
|
||||
raise strawberry.exceptions.StrawberryGraphQLError("Authentication required")
|
||||
|
||||
|
||||
def _require_admin(user: dict[str, Any] | None) -> None:
|
||||
"""Raise an error when the current user is not an admin.
|
||||
|
||||
When ``auth_enabled`` is *False* (single-user / development mode) all
|
||||
callers are implicitly treated as administrators.
|
||||
"""
|
||||
if not settings.auth_enabled:
|
||||
# Single-user mode: no auth, treat caller as admin
|
||||
return
|
||||
_require_auth(user)
|
||||
if not (user and user.get("is_admin")):
|
||||
raise strawberry.exceptions.StrawberryGraphQLError("Admin access required")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Query resolvers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@strawberry.type
|
||||
class Query:
|
||||
"""Root query type for the DocuElevate GraphQL API."""
|
||||
|
||||
@strawberry.field(description="List documents, optionally filtered by owner.")
|
||||
def documents(
|
||||
self,
|
||||
info: strawberry.types.Info,
|
||||
owner_id: str | None = None,
|
||||
limit: int = 20,
|
||||
offset: int = 0,
|
||||
) -> list[DocumentType]:
|
||||
"""Return a paginated list of documents.
|
||||
|
||||
When *auth_enabled* the caller must be authenticated. Non-admin users
|
||||
receive only their own documents; admins may query any *owner_id*.
|
||||
"""
|
||||
db, user = _get_db_and_user(info)
|
||||
_require_auth(user)
|
||||
|
||||
limit = max(1, min(limit, 100))
|
||||
offset = max(0, offset)
|
||||
|
||||
query = db.query(FileRecord)
|
||||
|
||||
if settings.auth_enabled and user:
|
||||
is_admin = user.get("is_admin", False)
|
||||
current_user_id = _get_current_user_id(user)
|
||||
if not is_admin:
|
||||
# Non-admins can only see their own documents
|
||||
query = query.filter(FileRecord.owner_id == current_user_id)
|
||||
elif owner_id:
|
||||
query = query.filter(FileRecord.owner_id == owner_id)
|
||||
elif owner_id:
|
||||
query = query.filter(FileRecord.owner_id == owner_id)
|
||||
|
||||
records = query.order_by(FileRecord.created_at.desc()).offset(offset).limit(limit).all()
|
||||
return [_document_from_record(r) for r in records]
|
||||
|
||||
@strawberry.field(description="Fetch a single document by ID.")
|
||||
def document(self, info: strawberry.types.Info, id: int) -> DocumentType | None:
|
||||
"""Return one document by its primary key, or *null* if not found."""
|
||||
db, user = _get_db_and_user(info)
|
||||
_require_auth(user)
|
||||
|
||||
rec = db.query(FileRecord).filter(FileRecord.id == id).first()
|
||||
if rec is None:
|
||||
return None
|
||||
|
||||
if settings.auth_enabled and user:
|
||||
is_admin = user.get("is_admin", False)
|
||||
current_user_id = _get_current_user_id(user)
|
||||
if not is_admin and rec.owner_id != current_user_id:
|
||||
return None
|
||||
|
||||
return _document_from_record(rec)
|
||||
|
||||
@strawberry.field(description="List processing pipelines.")
|
||||
def pipelines(
|
||||
self,
|
||||
info: strawberry.types.Info,
|
||||
owner_id: str | None = None,
|
||||
limit: int = 20,
|
||||
offset: int = 0,
|
||||
) -> list[PipelineType]:
|
||||
"""Return a paginated list of pipelines."""
|
||||
db, user = _get_db_and_user(info)
|
||||
_require_auth(user)
|
||||
|
||||
limit = max(1, min(limit, 100))
|
||||
offset = max(0, offset)
|
||||
|
||||
query = db.query(Pipeline)
|
||||
|
||||
if settings.auth_enabled and user:
|
||||
is_admin = user.get("is_admin", False)
|
||||
current_user_id = _get_current_user_id(user)
|
||||
if not is_admin:
|
||||
query = query.filter((Pipeline.owner_id == current_user_id) | (Pipeline.owner_id.is_(None)))
|
||||
elif owner_id:
|
||||
query = query.filter(Pipeline.owner_id == owner_id)
|
||||
elif owner_id:
|
||||
query = query.filter(Pipeline.owner_id == owner_id)
|
||||
|
||||
rows = query.order_by(Pipeline.id).offset(offset).limit(limit).all()
|
||||
return [_pipeline_from_record(p, db) for p in rows]
|
||||
|
||||
@strawberry.field(description="Fetch a single pipeline by ID.")
|
||||
def pipeline(self, info: strawberry.types.Info, id: int) -> PipelineType | None:
|
||||
"""Return one pipeline by its primary key, or *null* if not found."""
|
||||
db, user = _get_db_and_user(info)
|
||||
_require_auth(user)
|
||||
|
||||
row = db.query(Pipeline).filter(Pipeline.id == id).first()
|
||||
if row is None:
|
||||
return None
|
||||
|
||||
if settings.auth_enabled and user:
|
||||
is_admin = user.get("is_admin", False)
|
||||
current_user_id = _get_current_user_id(user)
|
||||
if not is_admin and row.owner_id is not None and row.owner_id != current_user_id:
|
||||
return None
|
||||
|
||||
return _pipeline_from_record(row, db)
|
||||
|
||||
@strawberry.field(description="List non-sensitive application settings (admin only).")
|
||||
def settings(
|
||||
self,
|
||||
info: strawberry.types.Info,
|
||||
limit: int = 50,
|
||||
offset: int = 0,
|
||||
) -> list[SettingType]:
|
||||
"""Return application settings stored in the database.
|
||||
|
||||
Sensitive keys (API secrets, passwords, etc.) are automatically
|
||||
excluded. Requires admin privileges when auth is enabled.
|
||||
"""
|
||||
db, user = _get_db_and_user(info)
|
||||
_require_admin(user)
|
||||
|
||||
limit = max(1, min(limit, 200))
|
||||
offset = max(0, offset)
|
||||
|
||||
rows = (
|
||||
db.query(ApplicationSettings)
|
||||
.filter(ApplicationSettings.key.notin_(_SENSITIVE_SETTING_KEYS))
|
||||
.order_by(ApplicationSettings.key)
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.all()
|
||||
)
|
||||
return [_setting_from_record(r) for r in rows]
|
||||
|
||||
@strawberry.field(description="List user profiles (admin only).")
|
||||
def users(
|
||||
self,
|
||||
info: strawberry.types.Info,
|
||||
limit: int = 20,
|
||||
offset: int = 0,
|
||||
) -> list[UserType]:
|
||||
"""Return a paginated list of user profiles. Requires admin privileges."""
|
||||
db, user = _get_db_and_user(info)
|
||||
_require_admin(user)
|
||||
|
||||
limit = max(1, min(limit, 100))
|
||||
offset = max(0, offset)
|
||||
|
||||
rows = db.query(UserProfile).order_by(UserProfile.user_id).offset(offset).limit(limit).all()
|
||||
return [_user_from_profile(r) for r in rows]
|
||||
|
||||
@strawberry.field(description="Fetch a user profile by user_id (admin only).")
|
||||
def user(self, info: strawberry.types.Info, user_id: str) -> UserType | None:
|
||||
"""Return one user profile by *user_id*, or *null* if not found."""
|
||||
db, user = _get_db_and_user(info)
|
||||
_require_admin(user)
|
||||
|
||||
row = db.query(UserProfile).filter(UserProfile.user_id == user_id).first()
|
||||
return _user_from_profile(row) if row else None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Schema and router
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
schema = strawberry.Schema(query=Query)
|
||||
|
||||
|
||||
async def get_graphql_context(
|
||||
request: Request,
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> dict[str, Any]:
|
||||
"""Build the per-request context injected into every resolver."""
|
||||
try:
|
||||
user = get_current_user(request)
|
||||
except Exception:
|
||||
logger.debug("Could not resolve current user for GraphQL context", exc_info=True)
|
||||
user = None
|
||||
return {"request": request, "db": db, "user": user}
|
||||
|
||||
|
||||
graphql_router = GraphQLRouter(
|
||||
schema,
|
||||
context_getter=get_graphql_context,
|
||||
graphql_ide="graphiql",
|
||||
)
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
"""API endpoints for internationalization (i18n).
|
||||
|
||||
Provides endpoints for:
|
||||
* Listing available languages
|
||||
* Getting/setting user language preference (persisted in session + cookie + DB)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, Request, Response
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import UserProfile
|
||||
from app.utils.i18n import (
|
||||
DEFAULT_LANGUAGE,
|
||||
SUPPORTED_LANGUAGE_CODES,
|
||||
SUPPORTED_LANGUAGES,
|
||||
detect_language,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/i18n", tags=["i18n"])
|
||||
|
||||
|
||||
class LanguageInfo(BaseModel):
|
||||
"""Schema for a supported language."""
|
||||
|
||||
code: str
|
||||
name: str
|
||||
native: str
|
||||
flag: str
|
||||
|
||||
|
||||
class LanguageListResponse(BaseModel):
|
||||
"""Response for the list-languages endpoint."""
|
||||
|
||||
languages: list[LanguageInfo]
|
||||
current: str
|
||||
default: str
|
||||
|
||||
|
||||
class SetLanguageRequest(BaseModel):
|
||||
"""Request body for setting the preferred language."""
|
||||
|
||||
language: str
|
||||
|
||||
|
||||
class SetLanguageResponse(BaseModel):
|
||||
"""Response after changing the language."""
|
||||
|
||||
language: str
|
||||
message: str
|
||||
|
||||
|
||||
@router.get("/languages", response_model=LanguageListResponse)
|
||||
async def list_languages(request: Request) -> LanguageListResponse:
|
||||
"""Return all supported UI languages and the current active language."""
|
||||
current = detect_language(request)
|
||||
return LanguageListResponse(
|
||||
languages=[LanguageInfo(**lang) for lang in SUPPORTED_LANGUAGES],
|
||||
current=current,
|
||||
default=DEFAULT_LANGUAGE,
|
||||
)
|
||||
|
||||
|
||||
@router.post("/language", response_model=SetLanguageResponse)
|
||||
async def set_language(
|
||||
body: SetLanguageRequest,
|
||||
request: Request,
|
||||
response: Response,
|
||||
db: Session = Depends(get_db),
|
||||
) -> SetLanguageResponse:
|
||||
"""Set the preferred UI language.
|
||||
|
||||
Persists the choice in:
|
||||
1. The server-side session
|
||||
2. A ``docuelevate_lang`` cookie (30-day expiry)
|
||||
3. The ``UserProfile.preferred_language`` column (if authenticated)
|
||||
"""
|
||||
lang = body.language.lower().strip()
|
||||
if lang not in SUPPORTED_LANGUAGE_CODES:
|
||||
lang = DEFAULT_LANGUAGE
|
||||
|
||||
# 1. Session
|
||||
if hasattr(request, "session"):
|
||||
request.session["preferred_language"] = lang
|
||||
|
||||
# 2. Cookie (30 days)
|
||||
response.set_cookie(
|
||||
key="docuelevate_lang",
|
||||
value=lang,
|
||||
max_age=30 * 24 * 60 * 60,
|
||||
httponly=False,
|
||||
samesite="lax",
|
||||
)
|
||||
|
||||
# 3. Database (if user is authenticated)
|
||||
_persist_language_to_profile(request, db, lang)
|
||||
|
||||
language_name = next(
|
||||
(entry["native"] for entry in SUPPORTED_LANGUAGES if entry["code"] == lang),
|
||||
lang,
|
||||
)
|
||||
logger.info("Language preference set to '%s'", lang)
|
||||
return SetLanguageResponse(
|
||||
language=lang,
|
||||
message=f"Language changed to {language_name}",
|
||||
)
|
||||
|
||||
|
||||
def _persist_language_to_profile(request: Request, db: Session, lang: str) -> None:
|
||||
"""Write language preference to the UserProfile row, if the user is logged in."""
|
||||
user_id: str | None = None
|
||||
if hasattr(request, "session"):
|
||||
user = request.session.get("user")
|
||||
if isinstance(user, dict):
|
||||
user_id = user.get("preferred_username") or user.get("email") or user.get("id")
|
||||
elif isinstance(user, str):
|
||||
user_id = user
|
||||
|
||||
if not user_id:
|
||||
return
|
||||
|
||||
try:
|
||||
profile = db.query(UserProfile).filter(UserProfile.user_id == user_id).first()
|
||||
if profile:
|
||||
profile.preferred_language = lang # type: ignore[attr-defined]
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
logger.debug("Could not persist language preference for user_id=%s", user_id)
|
||||
@@ -0,0 +1,347 @@
|
||||
"""Mobile app API endpoints.
|
||||
|
||||
Provides endpoints specifically designed for the DocuElevate native mobile
|
||||
app (iOS / Android via React Native / Expo):
|
||||
|
||||
* ``POST /mobile/generate-token`` – exchange an active session for a
|
||||
long-lived API token that the mobile app stores securely. The token is
|
||||
auto-named "Mobile App – <device_name>" and is identical to regular API
|
||||
tokens (Bearer auth works everywhere).
|
||||
|
||||
* ``POST /mobile/register-device`` – register a push-notification device
|
||||
token (Expo push token) so the user receives push notifications when
|
||||
documents finish processing.
|
||||
|
||||
* ``GET /mobile/devices`` – list registered devices for the current user.
|
||||
|
||||
* ``DELETE /mobile/devices/{device_id}`` – deactivate a device.
|
||||
|
||||
* ``GET /mobile/whoami`` – lightweight profile endpoint for the mobile app
|
||||
to verify authentication state.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from typing import Annotated, Any
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.api_tokens import generate_api_token, hash_token
|
||||
from app.auth import require_login
|
||||
from app.database import get_db
|
||||
from app.models import ApiToken, MobileDevice
|
||||
from app.utils.user_scope import get_current_owner_id
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/mobile", tags=["mobile"])
|
||||
|
||||
DbSession = Annotated[Session, Depends(get_db)]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Auth helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _get_owner_id(request: Request) -> str:
|
||||
"""Return the current user's owner ID, raising 401 if unauthenticated."""
|
||||
owner_id = get_current_owner_id(request)
|
||||
if not owner_id:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
|
||||
return owner_id
|
||||
|
||||
|
||||
CurrentOwner = Annotated[str, Depends(_get_owner_id)]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Request / Response schemas
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class GenerateTokenRequest(BaseModel):
|
||||
"""Request body for auto-generating a mobile app token."""
|
||||
|
||||
device_name: str = Field(
|
||||
default="Mobile App",
|
||||
min_length=1,
|
||||
max_length=120,
|
||||
description="Human-readable device name used to label the token.",
|
||||
)
|
||||
|
||||
|
||||
class GenerateTokenResponse(BaseModel):
|
||||
"""Response containing the one-time-visible API token."""
|
||||
|
||||
token: str
|
||||
token_id: int
|
||||
name: str
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class RegisterDeviceRequest(BaseModel):
|
||||
"""Request body for registering a push-notification device token."""
|
||||
|
||||
push_token: str = Field(
|
||||
min_length=1,
|
||||
max_length=512,
|
||||
description="Expo push token (ExponentPushToken[…]) obtained from the mobile app.",
|
||||
)
|
||||
device_name: str | None = Field(
|
||||
default=None,
|
||||
max_length=255,
|
||||
description="Optional human-readable device name (e.g. 'John's iPhone').",
|
||||
)
|
||||
platform: str = Field(
|
||||
default="ios",
|
||||
description="Device platform: 'ios', 'android', or 'web'.",
|
||||
)
|
||||
|
||||
|
||||
class DeviceResponse(BaseModel):
|
||||
"""Serialised MobileDevice record."""
|
||||
|
||||
id: int
|
||||
device_name: str | None
|
||||
platform: str
|
||||
push_token_preview: str
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
last_seen_at: datetime | None
|
||||
|
||||
|
||||
class WhoAmIResponse(BaseModel):
|
||||
"""Lightweight profile response for the mobile app."""
|
||||
|
||||
owner_id: str
|
||||
display_name: str | None
|
||||
email: str | None
|
||||
avatar_url: str | None
|
||||
is_admin: bool
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _device_to_response(device: MobileDevice) -> dict[str, Any]:
|
||||
"""Convert a MobileDevice ORM object to a serialisable dict."""
|
||||
# Show only first 20 chars of the push token for security.
|
||||
token_preview = device.push_token[:20] + "…" if len(device.push_token) > 20 else device.push_token
|
||||
return {
|
||||
"id": device.id,
|
||||
"device_name": device.device_name,
|
||||
"platform": device.platform,
|
||||
"push_token_preview": token_preview,
|
||||
"is_active": device.is_active,
|
||||
"created_at": device.created_at,
|
||||
"last_seen_at": device.last_seen_at,
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Endpoints
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@router.post("/generate-token", status_code=status.HTTP_201_CREATED, response_model=GenerateTokenResponse)
|
||||
@require_login
|
||||
async def generate_mobile_token(
|
||||
request: Request,
|
||||
body: GenerateTokenRequest,
|
||||
owner_id: CurrentOwner,
|
||||
db: DbSession,
|
||||
) -> dict[str, Any]:
|
||||
"""Generate a long-lived API token for the mobile app.
|
||||
|
||||
The mobile app calls this endpoint immediately after SSO login to obtain
|
||||
a Bearer token it can store in the secure keychain. The returned token
|
||||
is functionally identical to manually-created API tokens and works with
|
||||
every authenticated endpoint.
|
||||
|
||||
The token is shown **exactly once** in the response; subsequent requests
|
||||
show only the prefix for identification.
|
||||
"""
|
||||
token_name = f"Mobile App – {body.device_name}"
|
||||
plaintext = generate_api_token()
|
||||
token_hash_value = hash_token(plaintext)
|
||||
prefix = plaintext[:12]
|
||||
|
||||
db_token = ApiToken(
|
||||
owner_id=owner_id,
|
||||
name=token_name,
|
||||
token_hash=token_hash_value,
|
||||
token_prefix=prefix,
|
||||
)
|
||||
try:
|
||||
db.add(db_token)
|
||||
db.commit()
|
||||
db.refresh(db_token)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
logger.exception("Failed to create mobile API token for owner_id=%s", owner_id)
|
||||
raise
|
||||
|
||||
logger.info("Mobile API token created: id=%s owner=%s device=%r", db_token.id, owner_id, body.device_name)
|
||||
|
||||
return {
|
||||
"token": plaintext,
|
||||
"token_id": db_token.id,
|
||||
"name": token_name,
|
||||
"created_at": db_token.created_at,
|
||||
}
|
||||
|
||||
|
||||
@router.post("/register-device", status_code=status.HTTP_201_CREATED, response_model=DeviceResponse)
|
||||
@require_login
|
||||
async def register_device(
|
||||
request: Request,
|
||||
body: RegisterDeviceRequest,
|
||||
owner_id: CurrentOwner,
|
||||
db: DbSession,
|
||||
) -> dict[str, Any]:
|
||||
"""Register or refresh a push-notification device token.
|
||||
|
||||
If the same ``push_token`` is already registered for this user the
|
||||
record is reactivated and ``last_seen_at`` is updated rather than
|
||||
creating a duplicate.
|
||||
"""
|
||||
platform = body.platform.lower()
|
||||
if platform not in {"ios", "android", "web"}:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="platform must be one of: ios, android, web",
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
# Upsert: reuse existing record if the token is already known.
|
||||
existing = (
|
||||
db.query(MobileDevice)
|
||||
.filter(MobileDevice.owner_id == owner_id, MobileDevice.push_token == body.push_token)
|
||||
.first()
|
||||
)
|
||||
if existing:
|
||||
existing.is_active = True
|
||||
existing.last_seen_at = now
|
||||
if body.device_name:
|
||||
existing.device_name = body.device_name
|
||||
try:
|
||||
db.commit()
|
||||
db.refresh(existing)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise
|
||||
logger.info("Mobile device refreshed: id=%s owner=%s", existing.id, owner_id)
|
||||
return _device_to_response(existing)
|
||||
|
||||
device = MobileDevice(
|
||||
owner_id=owner_id,
|
||||
device_name=body.device_name,
|
||||
platform=platform,
|
||||
push_token=body.push_token,
|
||||
is_active=True,
|
||||
last_seen_at=now,
|
||||
)
|
||||
try:
|
||||
db.add(device)
|
||||
db.commit()
|
||||
db.refresh(device)
|
||||
except Exception:
|
||||
db.rollback()
|
||||
logger.exception("Failed to register mobile device for owner_id=%s", owner_id)
|
||||
raise
|
||||
|
||||
logger.info("Mobile device registered: id=%s owner=%s platform=%s", device.id, owner_id, platform)
|
||||
return _device_to_response(device)
|
||||
|
||||
|
||||
@router.get("/devices", response_model=list[DeviceResponse])
|
||||
@require_login
|
||||
async def list_devices(
|
||||
request: Request,
|
||||
owner_id: CurrentOwner,
|
||||
db: DbSession,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""List all registered push-notification devices for the current user."""
|
||||
devices = (
|
||||
db.query(MobileDevice).filter(MobileDevice.owner_id == owner_id).order_by(MobileDevice.created_at.desc()).all()
|
||||
)
|
||||
return [_device_to_response(d) for d in devices]
|
||||
|
||||
|
||||
@router.delete("/devices/{device_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@require_login
|
||||
async def deactivate_device(
|
||||
request: Request,
|
||||
device_id: int,
|
||||
owner_id: CurrentOwner,
|
||||
db: DbSession,
|
||||
) -> None:
|
||||
"""Deactivate a push-notification device registration.
|
||||
|
||||
The device record is kept for audit purposes but will no longer receive
|
||||
push notifications.
|
||||
"""
|
||||
device = db.get(MobileDevice, device_id)
|
||||
if not device or device.owner_id != owner_id:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Device not found")
|
||||
|
||||
device.is_active = False
|
||||
try:
|
||||
db.commit()
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
logger.info("Mobile device deactivated: id=%s owner=%s", device_id, owner_id)
|
||||
|
||||
|
||||
@router.get("/whoami", response_model=WhoAmIResponse)
|
||||
@require_login
|
||||
async def whoami(
|
||||
request: Request,
|
||||
owner_id: CurrentOwner,
|
||||
db: DbSession,
|
||||
) -> dict[str, Any]:
|
||||
"""Return basic profile information for the authenticated user.
|
||||
|
||||
The mobile app calls this after token exchange to populate the user
|
||||
profile screen and verify that the stored token is still valid.
|
||||
"""
|
||||
from app.auth import get_gravatar_url
|
||||
from app.models import LocalUser, UserProfile
|
||||
|
||||
profile = db.query(UserProfile).filter(UserProfile.user_id == owner_id).first()
|
||||
local_user = db.query(LocalUser).filter(LocalUser.email == owner_id).first()
|
||||
|
||||
display_name: str | None = None
|
||||
email: str | None = None
|
||||
avatar_url: str | None = None
|
||||
is_admin = False
|
||||
|
||||
if profile:
|
||||
display_name = profile.display_name
|
||||
|
||||
if local_user:
|
||||
email = local_user.email
|
||||
is_admin = bool(local_user.is_admin)
|
||||
if not display_name and local_user.display_name:
|
||||
display_name = local_user.display_name
|
||||
elif "@" in owner_id:
|
||||
# SSO users commonly have their email as owner_id
|
||||
email = owner_id
|
||||
|
||||
if email:
|
||||
avatar_url = get_gravatar_url(email)
|
||||
|
||||
return {
|
||||
"owner_id": owner_id,
|
||||
"display_name": display_name,
|
||||
"email": email,
|
||||
"avatar_url": avatar_url,
|
||||
"is_admin": is_admin,
|
||||
}
|
||||
@@ -857,6 +857,49 @@ class Settings(BaseSettings):
|
||||
),
|
||||
)
|
||||
|
||||
# SIEM / External Audit Log Forwarding
|
||||
# Forward audit events to external SIEM systems for centralised monitoring.
|
||||
audit_siem_enabled: bool = Field(
|
||||
default=False,
|
||||
description="Enable forwarding of audit events to an external SIEM system.",
|
||||
)
|
||||
audit_siem_transport: str = Field(
|
||||
default="syslog",
|
||||
description=(
|
||||
"Transport used to forward audit events. "
|
||||
"Options: 'syslog' (RFC 5424 over UDP/TCP), 'http' (JSON POST to a webhook URL, "
|
||||
"compatible with Splunk HEC, Logstash HTTP input, Grafana Loki, etc.)."
|
||||
),
|
||||
)
|
||||
audit_siem_syslog_host: str = Field(
|
||||
default="localhost",
|
||||
description="Hostname or IP of the syslog receiver.",
|
||||
)
|
||||
audit_siem_syslog_port: int = Field(
|
||||
default=514,
|
||||
description="Port of the syslog receiver.",
|
||||
)
|
||||
audit_siem_syslog_protocol: str = Field(
|
||||
default="udp",
|
||||
description="Protocol for syslog transport: 'udp' or 'tcp'.",
|
||||
)
|
||||
audit_siem_http_url: str = Field(
|
||||
default="",
|
||||
description=(
|
||||
"HTTP endpoint URL for SIEM webhook delivery. "
|
||||
"Supports Splunk HEC (https://splunk:8088/services/collector/event), "
|
||||
"Logstash HTTP input, Grafana Loki push API, or any JSON-accepting endpoint."
|
||||
),
|
||||
)
|
||||
audit_siem_http_token: str = Field(
|
||||
default="",
|
||||
description="Bearer / HEC token included in the Authorization header of SIEM HTTP requests.",
|
||||
)
|
||||
audit_siem_http_custom_headers: str = Field(
|
||||
default="",
|
||||
description="Comma-separated 'Key:Value' pairs of extra headers for SIEM HTTP requests.",
|
||||
)
|
||||
|
||||
# UI / Appearance
|
||||
ui_default_color_scheme: str = Field(
|
||||
default="system",
|
||||
|
||||
+22
-6
@@ -16,6 +16,7 @@ from starlette.middleware.trustedhost import TrustedHostMiddleware
|
||||
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
|
||||
|
||||
from app.api import router as api_router
|
||||
from app.api.graphql_api import graphql_router
|
||||
from app.api.local_auth import router as local_auth_router
|
||||
from app.auth import router as auth_router
|
||||
from app.config import settings
|
||||
@@ -253,6 +254,21 @@ else:
|
||||
|
||||
|
||||
# Custom exception handlers that return JSON for API routes and HTML for frontend routes
|
||||
# These use their own separate templates instance so that patches in tests on individual
|
||||
# view modules do not affect the error handler rendering.
|
||||
_error_templates_dir = pathlib.Path(__file__).parents[1] / "frontend" / "templates"
|
||||
_error_templates = Jinja2Templates(directory=str(_error_templates_dir))
|
||||
# Register the i18n translate helper as a global so error templates can use {{ _("key") }}.
|
||||
# Error pages use the default language (English); request-specific locale is not needed here.
|
||||
from app.utils.i18n import SUPPORTED_LANGUAGES as _SUPPORTED_LANGUAGES # noqa: E402
|
||||
from app.utils.i18n import translate as _translate_fn # noqa: E402
|
||||
|
||||
_error_templates.env.globals["_"] = lambda key, **kwargs: _translate_fn(key, "en", **kwargs)
|
||||
_error_templates.env.globals["min"] = min
|
||||
_error_templates.env.globals["max"] = max
|
||||
_error_templates.env.globals["supported_languages"] = _SUPPORTED_LANGUAGES
|
||||
|
||||
|
||||
@app.exception_handler(HTTPException)
|
||||
async def http_exception_handler(request: Request, exc: HTTPException):
|
||||
"""
|
||||
@@ -264,15 +280,15 @@ async def http_exception_handler(request: Request, exc: HTTPException):
|
||||
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
|
||||
|
||||
# For frontend routes, return appropriate HTML templates
|
||||
templates = Jinja2Templates(directory=str(static_dir.parent / "templates"))
|
||||
|
||||
# Handle 404 errors with a custom template
|
||||
if exc.status_code == 404:
|
||||
return templates.TemplateResponse("404.html", {"request": request}, status_code=status.HTTP_404_NOT_FOUND)
|
||||
return _error_templates.TemplateResponse(
|
||||
"404.html", {"request": request}, status_code=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
# For other HTTP errors, we could create specific templates or use a generic one
|
||||
# For now, return a simple error page
|
||||
return templates.TemplateResponse(
|
||||
return _error_templates.TemplateResponse(
|
||||
"404.html", # Reuse 404 template for other errors, or create a generic error template
|
||||
{"request": request},
|
||||
status_code=exc.status_code,
|
||||
@@ -293,8 +309,7 @@ async def custom_500_handler(request: Request, exc: Exception):
|
||||
)
|
||||
|
||||
# Serve the 500 template for non-API routes
|
||||
templates = Jinja2Templates(directory=str(static_dir.parent / "templates"))
|
||||
return templates.TemplateResponse(
|
||||
return _error_templates.TemplateResponse(
|
||||
"500.html",
|
||||
{"request": request, "exc": exc},
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
@@ -312,3 +327,4 @@ app.include_router(files_router) # Explicitly include the files router
|
||||
app.include_router(auth_router)
|
||||
app.include_router(local_auth_router)
|
||||
app.include_router(api_router, prefix="/api")
|
||||
app.include_router(graphql_router, prefix="/graphql")
|
||||
|
||||
@@ -146,6 +146,27 @@ class SettingsAuditLog(Base):
|
||||
action = Column(String, nullable=False) # "update" or "delete"
|
||||
|
||||
|
||||
class AuditLog(Base):
|
||||
"""Comprehensive audit log for compliance tracking.
|
||||
|
||||
Records all significant actions: login/logout, document CRUD, settings
|
||||
changes, and administrative operations. Rows are append-only; the API
|
||||
and service layer never update or delete entries.
|
||||
"""
|
||||
|
||||
__tablename__ = "audit_logs"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
timestamp = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True)
|
||||
user = Column(String, nullable=False, index=True) # Username or "anonymous" / "system"
|
||||
action = Column(String, nullable=False, index=True) # e.g. "login", "document.create", "settings.update"
|
||||
resource_type = Column(String, nullable=True, index=True) # e.g. "document", "user", "settings"
|
||||
resource_id = Column(String, nullable=True) # ID of the affected resource
|
||||
ip_address = Column(String, nullable=True) # Client IP address
|
||||
details = Column(Text, nullable=True) # JSON-encoded extra context
|
||||
severity = Column(String(16), nullable=False, server_default="info") # info / warning / error / critical
|
||||
|
||||
|
||||
class SavedSearch(Base):
|
||||
"""User-defined saved search filters for quick access to frequently used filter combinations."""
|
||||
|
||||
@@ -256,6 +277,10 @@ class UserProfile(Base):
|
||||
preferred_destination = Column(String(50), nullable=True)
|
||||
stripe_customer_id = Column(String(64), nullable=True)
|
||||
|
||||
# UI language preference for i18n (ISO 639-1 code, e.g. "en", "de", "fr")
|
||||
# NULL means "auto-detect from browser Accept-Language header"
|
||||
preferred_language = Column(String(10), nullable=True)
|
||||
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
@@ -835,6 +860,40 @@ class ScheduledJob(Base):
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
||||
|
||||
|
||||
class MobileDevice(Base):
|
||||
"""Registered mobile device for push notifications.
|
||||
|
||||
Stores the push token (Expo push token, FCM token, or APNs token) for a
|
||||
specific user device so that document-processing events can be forwarded
|
||||
as push notifications to the native mobile app.
|
||||
"""
|
||||
|
||||
__tablename__ = "mobile_devices"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
|
||||
# User that owns this device registration.
|
||||
owner_id = Column(String, nullable=False, index=True)
|
||||
|
||||
# Human-readable name the user gave this device (e.g. "John's iPhone").
|
||||
device_name = Column(String(255), nullable=True)
|
||||
|
||||
# Platform: "ios", "android", or "web".
|
||||
platform = Column(String(20), nullable=False, default="ios")
|
||||
|
||||
# Expo push token (ExponentPushToken[…]) or raw FCM/APNs token.
|
||||
push_token = Column(String(512), nullable=False)
|
||||
|
||||
# Whether push notifications are enabled for this device.
|
||||
is_active = Column(Boolean, nullable=False, default=True)
|
||||
|
||||
# Timestamps.
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||
last_seen_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
__table_args__ = (UniqueConstraint("owner_id", "push_token", name="uq_mobile_device_owner_token"),)
|
||||
|
||||
|
||||
class ComplianceTemplate(Base):
|
||||
"""Pre-built compliance configuration templates (GDPR, HIPAA, SOC2).
|
||||
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
"""
|
||||
Comprehensive audit-event service for DocuElevate.
|
||||
|
||||
Provides helpers to **record** audit events (append-only database writes)
|
||||
and to optionally **forward** them to external SIEM systems.
|
||||
|
||||
Supported SIEM transports:
|
||||
* **Syslog** – RFC 5424 structured-data messages over UDP or TCP.
|
||||
* **HTTP** – JSON POST payloads compatible with Splunk HEC, Logstash
|
||||
HTTP input, Grafana Loki push API, and any generic webhook endpoint.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import socket
|
||||
import threading
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
from fastapi import Request
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.config import settings
|
||||
from app.middleware.audit_log import get_client_ip, get_username
|
||||
from app.models import AuditLog
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def record_event(
|
||||
db: Session,
|
||||
*,
|
||||
action: str,
|
||||
user: str = "system",
|
||||
resource_type: str | None = None,
|
||||
resource_id: str | None = None,
|
||||
ip_address: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
severity: str = "info",
|
||||
) -> AuditLog:
|
||||
"""Persist an audit event and optionally forward it to SIEM.
|
||||
|
||||
Args:
|
||||
db: Active SQLAlchemy session.
|
||||
action: Short action identifier (e.g. ``"login"``, ``"document.create"``).
|
||||
user: Username performing the action.
|
||||
resource_type: Category of the affected resource (``"document"``, ``"user"`` …).
|
||||
resource_id: Identifier of the affected resource.
|
||||
ip_address: Client IP address (``None`` when not applicable).
|
||||
details: Arbitrary key/value context serialised as JSON.
|
||||
severity: One of ``info``, ``warning``, ``error``, ``critical``.
|
||||
|
||||
Returns:
|
||||
The newly created :class:`AuditLog` row.
|
||||
"""
|
||||
details_json = json.dumps(details, default=str) if details else None
|
||||
|
||||
entry = AuditLog(
|
||||
user=user,
|
||||
action=action,
|
||||
resource_type=resource_type,
|
||||
resource_id=str(resource_id) if resource_id is not None else None,
|
||||
ip_address=ip_address,
|
||||
details=details_json,
|
||||
severity=severity,
|
||||
)
|
||||
db.add(entry)
|
||||
db.commit()
|
||||
db.refresh(entry)
|
||||
|
||||
# Fire-and-forget SIEM forwarding in a background thread so we never
|
||||
# block the request path.
|
||||
if settings.audit_siem_enabled:
|
||||
payload = _build_siem_payload(entry)
|
||||
thread = threading.Thread(target=_forward_to_siem, args=(payload,), daemon=True)
|
||||
thread.start()
|
||||
|
||||
return entry
|
||||
|
||||
|
||||
def record_event_from_request(
|
||||
db: Session,
|
||||
request: Request,
|
||||
*,
|
||||
action: str,
|
||||
resource_type: str | None = None,
|
||||
resource_id: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
severity: str = "info",
|
||||
) -> AuditLog:
|
||||
"""Convenience wrapper that extracts user and IP from a :class:`Request`.
|
||||
|
||||
Args:
|
||||
db: Active SQLAlchemy session.
|
||||
request: The current HTTP request.
|
||||
action: Short action identifier.
|
||||
resource_type: Category of the affected resource.
|
||||
resource_id: Identifier of the affected resource.
|
||||
details: Arbitrary key/value context serialised as JSON.
|
||||
severity: One of ``info``, ``warning``, ``error``, ``critical``.
|
||||
|
||||
Returns:
|
||||
The newly created :class:`AuditLog` row.
|
||||
"""
|
||||
return record_event(
|
||||
db,
|
||||
action=action,
|
||||
user=get_username(request),
|
||||
resource_type=resource_type,
|
||||
resource_id=resource_id,
|
||||
ip_address=get_client_ip(request),
|
||||
details=details,
|
||||
severity=severity,
|
||||
)
|
||||
|
||||
|
||||
def query_events(
|
||||
db: Session,
|
||||
*,
|
||||
action: str | None = None,
|
||||
user: str | None = None,
|
||||
resource_type: str | None = None,
|
||||
severity: str | None = None,
|
||||
since: datetime | None = None,
|
||||
until: datetime | None = None,
|
||||
limit: int = 200,
|
||||
offset: int = 0,
|
||||
) -> list[AuditLog]:
|
||||
"""Query audit log entries with optional filtering.
|
||||
|
||||
Args:
|
||||
db: Active SQLAlchemy session.
|
||||
action: Filter by action string (exact match).
|
||||
user: Filter by username (exact match).
|
||||
resource_type: Filter by resource type (exact match).
|
||||
severity: Filter by severity level (exact match).
|
||||
since: Only events at or after this timestamp.
|
||||
until: Only events at or before this timestamp.
|
||||
limit: Maximum number of rows to return.
|
||||
offset: Number of rows to skip (for pagination).
|
||||
|
||||
Returns:
|
||||
List of :class:`AuditLog` rows ordered by *timestamp descending*.
|
||||
"""
|
||||
q = db.query(AuditLog)
|
||||
if action:
|
||||
q = q.filter(AuditLog.action == action)
|
||||
if user:
|
||||
q = q.filter(AuditLog.user == user)
|
||||
if resource_type:
|
||||
q = q.filter(AuditLog.resource_type == resource_type)
|
||||
if severity:
|
||||
q = q.filter(AuditLog.severity == severity)
|
||||
if since:
|
||||
q = q.filter(AuditLog.timestamp >= since)
|
||||
if until:
|
||||
q = q.filter(AuditLog.timestamp <= until)
|
||||
return q.order_by(AuditLog.timestamp.desc()).offset(offset).limit(limit).all()
|
||||
|
||||
|
||||
def count_events(
|
||||
db: Session,
|
||||
*,
|
||||
action: str | None = None,
|
||||
user: str | None = None,
|
||||
resource_type: str | None = None,
|
||||
severity: str | None = None,
|
||||
since: datetime | None = None,
|
||||
until: datetime | None = None,
|
||||
) -> int:
|
||||
"""Return the total count of events matching the given filters.
|
||||
|
||||
Args:
|
||||
db: Active SQLAlchemy session.
|
||||
action: Filter by action string.
|
||||
user: Filter by username.
|
||||
resource_type: Filter by resource type.
|
||||
severity: Filter by severity level.
|
||||
since: Only events at or after this timestamp.
|
||||
until: Only events at or before this timestamp.
|
||||
|
||||
Returns:
|
||||
Integer count.
|
||||
"""
|
||||
q = db.query(AuditLog)
|
||||
if action:
|
||||
q = q.filter(AuditLog.action == action)
|
||||
if user:
|
||||
q = q.filter(AuditLog.user == user)
|
||||
if resource_type:
|
||||
q = q.filter(AuditLog.resource_type == resource_type)
|
||||
if severity:
|
||||
q = q.filter(AuditLog.severity == severity)
|
||||
if since:
|
||||
q = q.filter(AuditLog.timestamp >= since)
|
||||
if until:
|
||||
q = q.filter(AuditLog.timestamp <= until)
|
||||
return q.count()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SIEM forwarding internals
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_SYSLOG_FACILITY_LOCAL0 = 16
|
||||
_SYSLOG_SEVERITY_MAP = {
|
||||
"info": 6,
|
||||
"warning": 4,
|
||||
"error": 3,
|
||||
"critical": 2,
|
||||
}
|
||||
|
||||
|
||||
def _build_siem_payload(entry: AuditLog) -> dict[str, Any]:
|
||||
"""Convert an :class:`AuditLog` row into a plain dict for SIEM delivery."""
|
||||
ts = entry.timestamp if entry.timestamp else datetime.now(timezone.utc)
|
||||
return {
|
||||
"id": entry.id,
|
||||
"timestamp": ts.isoformat(),
|
||||
"user": entry.user,
|
||||
"action": entry.action,
|
||||
"resource_type": entry.resource_type,
|
||||
"resource_id": entry.resource_id,
|
||||
"ip_address": entry.ip_address,
|
||||
"details": entry.details,
|
||||
"severity": entry.severity,
|
||||
"source": "docuelevate",
|
||||
}
|
||||
|
||||
|
||||
def _forward_to_siem(payload: dict[str, Any]) -> None:
|
||||
"""Route a SIEM payload to the configured transport."""
|
||||
transport = settings.audit_siem_transport.lower()
|
||||
try:
|
||||
if transport == "syslog":
|
||||
_send_syslog(payload)
|
||||
elif transport == "http":
|
||||
_send_http(payload)
|
||||
else:
|
||||
logger.warning("Unknown SIEM transport %r; skipping forwarding", transport)
|
||||
except Exception:
|
||||
logger.exception("Failed to forward audit event to SIEM (%s)", transport)
|
||||
|
||||
|
||||
def _send_syslog(payload: dict[str, Any]) -> None:
|
||||
"""Send a RFC 5424 syslog message to the configured receiver."""
|
||||
severity_num = _SYSLOG_SEVERITY_MAP.get(payload.get("severity", "info"), 6)
|
||||
priority = _SYSLOG_FACILITY_LOCAL0 * 8 + severity_num
|
||||
ts = payload.get("timestamp", datetime.now(timezone.utc).isoformat())
|
||||
hostname = socket.gethostname()
|
||||
app_name = "docuelevate"
|
||||
msg_id = payload.get("action", "-")
|
||||
|
||||
# Structured data (SD) element with key event fields.
|
||||
sd = (
|
||||
f'[docuelevate@0 user="{payload.get("user", "-")}" '
|
||||
f'action="{payload.get("action", "-")}" '
|
||||
f'resource_type="{payload.get("resource_type", "-")}" '
|
||||
f'resource_id="{payload.get("resource_id", "-")}" '
|
||||
f'ip="{payload.get("ip_address", "-")}"]'
|
||||
)
|
||||
message = json.dumps(payload, default=str)
|
||||
syslog_msg = f"<{priority}>1 {ts} {hostname} {app_name} - {msg_id} {sd} {message}"
|
||||
|
||||
proto = settings.audit_siem_syslog_protocol.lower()
|
||||
host = settings.audit_siem_syslog_host
|
||||
port = settings.audit_siem_syslog_port
|
||||
|
||||
if proto == "tcp":
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||
sock.settimeout(5)
|
||||
sock.connect((host, port))
|
||||
sock.sendall(syslog_msg.encode("utf-8"))
|
||||
else:
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||
sock.settimeout(5)
|
||||
sock.sendto(syslog_msg.encode("utf-8"), (host, port))
|
||||
|
||||
logger.debug("Syslog audit event sent to %s:%s (%s)", host, port, proto)
|
||||
|
||||
|
||||
def _send_http(payload: dict[str, Any]) -> None:
|
||||
"""POST a JSON audit event to the configured HTTP endpoint."""
|
||||
url = settings.audit_siem_http_url
|
||||
if not url:
|
||||
logger.warning("SIEM HTTP URL not configured; skipping HTTP forwarding")
|
||||
return
|
||||
|
||||
headers: dict[str, str] = {"Content-Type": "application/json"}
|
||||
token = settings.audit_siem_http_token
|
||||
if token:
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
|
||||
# Parse custom headers (comma-separated "Key:Value" pairs).
|
||||
# Reject headers that could override security-critical ones already set,
|
||||
# and validate that header names contain only RFC 7230 token characters.
|
||||
_PROTECTED_HEADERS = {"authorization", "content-type", "host"}
|
||||
_VALID_HEADER_NAME = re.compile(r"^[A-Za-z0-9!#$%&'*+\-.^_`|~]+$")
|
||||
raw_custom = settings.audit_siem_http_custom_headers
|
||||
if raw_custom:
|
||||
for raw_pair in raw_custom.split(","):
|
||||
pair = raw_pair.strip()
|
||||
if ":" in pair:
|
||||
k, _, v = pair.partition(":")
|
||||
name = k.strip()
|
||||
if not name or not _VALID_HEADER_NAME.match(name):
|
||||
logger.warning("Skipping invalid SIEM custom header name: %r", name)
|
||||
continue
|
||||
if name.lower() in _PROTECTED_HEADERS:
|
||||
logger.warning("Skipping protected SIEM custom header: %r", name)
|
||||
continue
|
||||
headers[name] = v.strip()
|
||||
|
||||
# Wrap in Splunk HEC-style envelope when URL contains ``/services/collector``.
|
||||
body: dict[str, Any]
|
||||
if "/services/collector" in url:
|
||||
body = {"event": payload, "sourcetype": "docuelevate:audit", "source": "docuelevate"}
|
||||
else:
|
||||
body = payload
|
||||
|
||||
with httpx.Client(timeout=10) as client:
|
||||
resp = client.post(url, json=body, headers=headers)
|
||||
resp.raise_for_status()
|
||||
|
||||
logger.debug("HTTP audit event forwarded to %s (status %s)", url, resp.status_code)
|
||||
@@ -32,8 +32,10 @@ _TABLE_ORDER = [
|
||||
"processing_logs",
|
||||
"application_settings",
|
||||
"settings_audit_log",
|
||||
"audit_logs",
|
||||
"saved_searches",
|
||||
"webhook_configs",
|
||||
"shared_links",
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,542 @@
|
||||
"""Internationalization (i18n) and localization (l10n) utilities.
|
||||
|
||||
Provides a JSON-based translation system for the DocuElevate UI with:
|
||||
|
||||
* **31 supported languages** covering all major European languages plus ZH
|
||||
* Browser ``Accept-Language`` detection with cookie & user-profile persistence
|
||||
* AI-powered fallback translation via the configured LLM provider
|
||||
* Locale-aware date, number, and file-size formatting helpers
|
||||
* Jinja2 integration via a ``_()`` global function
|
||||
|
||||
Language resolution order:
|
||||
1. User profile ``preferred_language`` (persisted in DB)
|
||||
2. ``docuelevate_lang`` cookie
|
||||
3. ``Accept-Language`` HTTP header
|
||||
4. Default (``en``)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from datetime import date, datetime
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from starlette.requests import Request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Supported languages (ordered by priority)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
SUPPORTED_LANGUAGES: list[dict[str, str]] = [
|
||||
# --- Tier 1: Primary European languages ---
|
||||
{"code": "en", "name": "English", "native": "English", "flag": "🇬🇧"},
|
||||
{"code": "de", "name": "German", "native": "Deutsch", "flag": "🇩🇪"},
|
||||
{"code": "fr", "name": "French", "native": "Français", "flag": "🇫🇷"},
|
||||
{"code": "es", "name": "Spanish", "native": "Español", "flag": "🇪🇸"},
|
||||
{"code": "it", "name": "Italian", "native": "Italiano", "flag": "🇮🇹"},
|
||||
{"code": "pt", "name": "Portuguese", "native": "Português", "flag": "🇵🇹"},
|
||||
# --- Tier 2: Western & Northern European ---
|
||||
{"code": "nl", "name": "Dutch", "native": "Nederlands", "flag": "🇳🇱"},
|
||||
{"code": "nb", "name": "Norwegian", "native": "Norsk", "flag": "🇳🇴"},
|
||||
{"code": "da", "name": "Danish", "native": "Dansk", "flag": "🇩🇰"},
|
||||
{"code": "sv", "name": "Swedish", "native": "Svenska", "flag": "🇸🇪"},
|
||||
{"code": "fi", "name": "Finnish", "native": "Suomi", "flag": "🇫🇮"},
|
||||
{"code": "is", "name": "Icelandic", "native": "Íslenska", "flag": "🇮🇸"},
|
||||
{"code": "ga", "name": "Irish", "native": "Gaeilge", "flag": "🇮🇪"},
|
||||
{"code": "lb", "name": "Luxembourgish", "native": "Lëtzebuergesch", "flag": "🇱🇺"},
|
||||
{"code": "ca", "name": "Catalan", "native": "Català", "flag": "🏴"},
|
||||
# --- Tier 3: Central & Eastern European ---
|
||||
{"code": "pl", "name": "Polish", "native": "Polski", "flag": "🇵🇱"},
|
||||
{"code": "cs", "name": "Czech", "native": "Čeština", "flag": "🇨🇿"},
|
||||
{"code": "sk", "name": "Slovak", "native": "Slovenčina", "flag": "🇸🇰"},
|
||||
{"code": "hu", "name": "Hungarian", "native": "Magyar", "flag": "🇭🇺"},
|
||||
{"code": "sl", "name": "Slovenian", "native": "Slovenščina", "flag": "🇸🇮"},
|
||||
{"code": "hr", "name": "Croatian", "native": "Hrvatski", "flag": "🇭🇷"},
|
||||
{"code": "ro", "name": "Romanian", "native": "Română", "flag": "🇷🇴"},
|
||||
{"code": "bg", "name": "Bulgarian", "native": "Български", "flag": "🇧🇬"},
|
||||
{"code": "el", "name": "Greek", "native": "Ελληνικά", "flag": "🇬🇷"},
|
||||
{"code": "et", "name": "Estonian", "native": "Eesti", "flag": "🇪🇪"},
|
||||
{"code": "lv", "name": "Latvian", "native": "Latviešu", "flag": "🇱🇻"},
|
||||
{"code": "lt", "name": "Lithuanian", "native": "Lietuvių", "flag": "🇱🇹"},
|
||||
# --- Tier 4: Non-EU European & Other ---
|
||||
{"code": "tr", "name": "Turkish", "native": "Türkçe", "flag": "🇹🇷"},
|
||||
{"code": "uk", "name": "Ukrainian", "native": "Українська", "flag": "🇺🇦"},
|
||||
{"code": "ru", "name": "Russian", "native": "Русский", "flag": "🇷🇺"},
|
||||
{"code": "zh", "name": "Chinese", "native": "中文", "flag": "🇨🇳"},
|
||||
]
|
||||
|
||||
SUPPORTED_LANGUAGE_CODES: set[str] = {lang["code"] for lang in SUPPORTED_LANGUAGES}
|
||||
DEFAULT_LANGUAGE = "en"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Translation file loading
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_TRANSLATIONS_DIR = Path(__file__).resolve().parent.parent.parent / "frontend" / "translations"
|
||||
_translation_cache: dict[str, dict[str, str]] = {}
|
||||
|
||||
|
||||
def _load_translations(locale: str) -> dict[str, str]:
|
||||
"""Load the translation JSON file for *locale*, with caching."""
|
||||
if locale in _translation_cache:
|
||||
return _translation_cache[locale]
|
||||
|
||||
filepath = _TRANSLATIONS_DIR / f"{locale}.json"
|
||||
if not filepath.is_file():
|
||||
logger.warning("Translation file not found for locale '%s'", locale)
|
||||
_translation_cache[locale] = {}
|
||||
return {}
|
||||
|
||||
try:
|
||||
data: dict[str, str] = json.loads(filepath.read_text(encoding="utf-8"))
|
||||
_translation_cache[locale] = data
|
||||
return data
|
||||
except (json.JSONDecodeError, OSError):
|
||||
logger.exception("Failed to load translations for '%s'", locale)
|
||||
_translation_cache[locale] = {}
|
||||
return {}
|
||||
|
||||
|
||||
def reload_translations() -> None:
|
||||
"""Clear the translation cache so files are re-read on next access."""
|
||||
_translation_cache.clear()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Core translation function
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def translate(key: str, locale: str | None = None, **kwargs: Any) -> str:
|
||||
"""Return the translated string for *key* in *locale*.
|
||||
|
||||
Falls back through:
|
||||
1. Requested *locale*
|
||||
2. English (``en``)
|
||||
3. The raw key itself (to keep the UI functional)
|
||||
|
||||
Positional placeholders ``{0}``, ``{1}`` or named placeholders
|
||||
``{name}`` in the translated string are interpolated via *kwargs*.
|
||||
"""
|
||||
locale = locale if locale and locale in SUPPORTED_LANGUAGE_CODES else DEFAULT_LANGUAGE
|
||||
|
||||
translations = _load_translations(locale)
|
||||
value = translations.get(key)
|
||||
|
||||
# Fallback to English
|
||||
if value is None and locale != DEFAULT_LANGUAGE:
|
||||
en_translations = _load_translations(DEFAULT_LANGUAGE)
|
||||
value = en_translations.get(key)
|
||||
|
||||
# Fallback to key itself
|
||||
if value is None:
|
||||
value = key
|
||||
|
||||
if kwargs:
|
||||
try:
|
||||
value = value.format(**kwargs)
|
||||
except (KeyError, IndexError):
|
||||
pass # Return unformatted string rather than crash
|
||||
|
||||
return value
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AI fallback translation (best-effort, non-blocking)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_ai_translation_cache: dict[tuple[str, str], str] = {}
|
||||
|
||||
|
||||
def translate_with_ai_fallback(text: str, target_locale: str) -> str:
|
||||
"""Translate *text* using the configured AI provider as a fallback.
|
||||
|
||||
Returns the original *text* unchanged when:
|
||||
* The target locale is English (source language)
|
||||
* The AI provider is unavailable or returns an error
|
||||
* The translation has already been cached
|
||||
|
||||
Results are cached in-memory for the lifetime of the process.
|
||||
"""
|
||||
if target_locale == DEFAULT_LANGUAGE or target_locale not in SUPPORTED_LANGUAGE_CODES:
|
||||
return text
|
||||
|
||||
cache_key = (text, target_locale)
|
||||
if cache_key in _ai_translation_cache:
|
||||
return _ai_translation_cache[cache_key]
|
||||
|
||||
target_name = next(
|
||||
(lang["name"] for lang in SUPPORTED_LANGUAGES if lang["code"] == target_locale),
|
||||
target_locale,
|
||||
)
|
||||
|
||||
try:
|
||||
from litellm import completion # type: ignore[import-untyped]
|
||||
|
||||
from app.config import settings
|
||||
|
||||
model = getattr(settings, "ai_model", None) or getattr(settings, "openai_model", "gpt-4o-mini")
|
||||
response = completion(
|
||||
model=model,
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": (
|
||||
f"You are a professional translator. Translate the following UI text "
|
||||
f"from English to {target_name}. Return ONLY the translated text, "
|
||||
f"nothing else. Keep any HTML tags, placeholders like {{name}}, "
|
||||
f"and special characters intact."
|
||||
),
|
||||
},
|
||||
{"role": "user", "content": text},
|
||||
],
|
||||
max_tokens=256,
|
||||
temperature=0.1,
|
||||
)
|
||||
translated = response.choices[0].message.content.strip()
|
||||
_ai_translation_cache[cache_key] = translated
|
||||
return translated
|
||||
except Exception:
|
||||
logger.debug("AI fallback translation failed for '%s' → %s", text[:50], target_locale)
|
||||
return text
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Language detection
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def detect_language(request: Request) -> str:
|
||||
"""Determine the preferred UI language from the request context.
|
||||
|
||||
Resolution order:
|
||||
1. ``preferred_language`` stored in the user session
|
||||
2. ``docuelevate_lang`` cookie
|
||||
3. ``Accept-Language`` HTTP header (best match)
|
||||
4. Default → ``en``
|
||||
"""
|
||||
# 1. User session preference
|
||||
if hasattr(request, "session"):
|
||||
session_lang = request.session.get("preferred_language")
|
||||
if isinstance(session_lang, str) and session_lang in SUPPORTED_LANGUAGE_CODES:
|
||||
return session_lang
|
||||
|
||||
# 2. Cookie
|
||||
if hasattr(request, "cookies"):
|
||||
cookie_lang = request.cookies.get("docuelevate_lang")
|
||||
if isinstance(cookie_lang, str) and cookie_lang in SUPPORTED_LANGUAGE_CODES:
|
||||
return cookie_lang
|
||||
|
||||
# 3. Accept-Language header
|
||||
accept = ""
|
||||
if hasattr(request, "headers"):
|
||||
accept = request.headers.get("accept-language", "")
|
||||
lang = _parse_accept_language(accept)
|
||||
if lang:
|
||||
return lang
|
||||
|
||||
return DEFAULT_LANGUAGE
|
||||
|
||||
|
||||
def _parse_accept_language(header: str) -> str | None:
|
||||
"""Extract the best matching language from an ``Accept-Language`` header.
|
||||
|
||||
Parses quality values and returns the highest-priority match among
|
||||
:data:`SUPPORTED_LANGUAGE_CODES`, or ``None`` if nothing matches.
|
||||
"""
|
||||
if not header:
|
||||
return None
|
||||
|
||||
entries: list[tuple[float, str]] = []
|
||||
for raw_part in header.split(","):
|
||||
part = raw_part.strip()
|
||||
if not part:
|
||||
continue
|
||||
if ";q=" in part:
|
||||
lang_tag, _, q_str = part.partition(";q=")
|
||||
try:
|
||||
quality = float(q_str.strip())
|
||||
except ValueError:
|
||||
quality = 0.0
|
||||
else:
|
||||
lang_tag = part
|
||||
quality = 1.0
|
||||
entries.append((quality, lang_tag.strip().lower()))
|
||||
|
||||
# Sort by quality descending
|
||||
entries.sort(key=lambda e: e[0], reverse=True)
|
||||
|
||||
for _quality, tag in entries:
|
||||
# Try exact match first (e.g., "de", "zh")
|
||||
code = tag.split("-")[0]
|
||||
if code in SUPPORTED_LANGUAGE_CODES:
|
||||
return code
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Localization helpers (l10n)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Locale-specific formatting rules for date/number display
|
||||
_LOCALE_FORMATS: dict[str, dict[str, Any]] = {
|
||||
"en": {
|
||||
"date": "%B %d, %Y",
|
||||
"date_short": "%m/%d/%Y",
|
||||
"datetime": "%B %d, %Y %I:%M %p",
|
||||
"thousands_sep": ",",
|
||||
"decimal_sep": ".",
|
||||
},
|
||||
"de": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"fr": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d/%m/%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": "\u202f",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"es": {
|
||||
"date": "%d de %B de %Y",
|
||||
"date_short": "%d/%m/%Y",
|
||||
"datetime": "%d de %B de %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"it": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d/%m/%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"pt": {
|
||||
"date": "%d de %B de %Y",
|
||||
"date_short": "%d/%m/%Y",
|
||||
"datetime": "%d de %B de %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"nl": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d-%m-%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"nb": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"da": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"sv": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%Y-%m-%d",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"fi": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"is": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"ga": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d/%m/%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": ",",
|
||||
"decimal_sep": ".",
|
||||
},
|
||||
"lb": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"ca": {
|
||||
"date": "%d de %B de %Y",
|
||||
"date_short": "%d/%m/%Y",
|
||||
"datetime": "%d de %B de %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"pl": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"cs": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"sk": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"hu": {
|
||||
"date": "%Y. %B %d.",
|
||||
"date_short": "%Y.%m.%d.",
|
||||
"datetime": "%Y. %B %d. %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"sl": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"hr": {
|
||||
"date": "%d. %B %Y.",
|
||||
"date_short": "%d.%m.%Y.",
|
||||
"datetime": "%d. %B %Y. %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"ro": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"bg": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"el": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d/%m/%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"et": {
|
||||
"date": "%d. %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d. %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"lv": {
|
||||
"date": "%Y. gada %d. %B",
|
||||
"date_short": "%d.%m.%Y.",
|
||||
"datetime": "%Y. gada %d. %B %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"lt": {
|
||||
"date": "%Y m. %B %d d.",
|
||||
"date_short": "%Y-%m-%d",
|
||||
"datetime": "%Y m. %B %d d. %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"tr": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": ".",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"uk": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
"zh": {
|
||||
"date": "%Y年%m月%d日",
|
||||
"date_short": "%Y/%m/%d",
|
||||
"datetime": "%Y年%m月%d日 %H:%M",
|
||||
"thousands_sep": ",",
|
||||
"decimal_sep": ".",
|
||||
},
|
||||
"ru": {
|
||||
"date": "%d %B %Y",
|
||||
"date_short": "%d.%m.%Y",
|
||||
"datetime": "%d %B %Y %H:%M",
|
||||
"thousands_sep": "\u00a0",
|
||||
"decimal_sep": ",",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def format_date(value: date | datetime | None, locale: str = DEFAULT_LANGUAGE, short: bool = False) -> str:
|
||||
"""Format a date/datetime value according to the locale conventions."""
|
||||
if value is None:
|
||||
return ""
|
||||
fmt_key = "date_short" if short else "date"
|
||||
fmt = _LOCALE_FORMATS.get(locale, _LOCALE_FORMATS[DEFAULT_LANGUAGE])[fmt_key]
|
||||
return value.strftime(fmt)
|
||||
|
||||
|
||||
def format_datetime(value: datetime | None, locale: str = DEFAULT_LANGUAGE) -> str:
|
||||
"""Format a datetime value according to the locale conventions."""
|
||||
if value is None:
|
||||
return ""
|
||||
fmt = _LOCALE_FORMATS.get(locale, _LOCALE_FORMATS[DEFAULT_LANGUAGE])["datetime"]
|
||||
return value.strftime(fmt)
|
||||
|
||||
|
||||
def format_number(value: int | float, locale: str = DEFAULT_LANGUAGE) -> str:
|
||||
"""Format a number with locale-appropriate thousand separators."""
|
||||
lf = _LOCALE_FORMATS.get(locale, _LOCALE_FORMATS[DEFAULT_LANGUAGE])
|
||||
if isinstance(value, float):
|
||||
int_part, _, dec_part = f"{value:,.2f}".partition(".")
|
||||
formatted_int = int_part.replace(",", lf["thousands_sep"])
|
||||
return f"{formatted_int}{lf['decimal_sep']}{dec_part}"
|
||||
return f"{value:,}".replace(",", lf["thousands_sep"])
|
||||
|
||||
|
||||
@lru_cache(maxsize=32)
|
||||
def get_language_info(code: str) -> dict[str, str] | None:
|
||||
"""Return the metadata dict for a supported language code, or ``None``."""
|
||||
for lang in SUPPORTED_LANGUAGES:
|
||||
if lang["code"] == code:
|
||||
return lang
|
||||
return None
|
||||
@@ -0,0 +1,130 @@
|
||||
"""Push notification sender for the DocuElevate mobile app.
|
||||
|
||||
Uses the **Expo Push Notification** service to deliver notifications to both
|
||||
iOS (via APNs) and Android (via FCM) without requiring server-side APNs keys
|
||||
or FCM credentials. The mobile app obtains an ``ExponentPushToken[…]`` at
|
||||
startup and registers it with the backend via the mobile API.
|
||||
|
||||
Reference: https://docs.expo.dev/push-notifications/sending-notifications/
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
from app.database import SessionLocal
|
||||
from app.models import MobileDevice
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
EXPO_PUSH_URL = "https://exp.host/--/api/v2/push/send"
|
||||
|
||||
# Maximum tokens per batch request (Expo limit).
|
||||
_EXPO_BATCH_LIMIT = 100
|
||||
|
||||
|
||||
def send_expo_push_notification(
|
||||
tokens: list[str],
|
||||
title: str,
|
||||
body: str,
|
||||
data: dict[str, Any] | None = None,
|
||||
sound: str = "default",
|
||||
badge: int | None = None,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Send a push notification to one or more Expo push tokens.
|
||||
|
||||
Args:
|
||||
tokens: List of Expo push tokens (``ExponentPushToken[…]``).
|
||||
title: Notification title shown in the system tray.
|
||||
body: Notification body text.
|
||||
data: Optional JSON-serialisable dict attached to the notification
|
||||
(available in the app via ``notification.request.content.data``).
|
||||
sound: Notification sound. Use ``"default"`` or ``None`` for silent.
|
||||
badge: iOS badge count. Pass ``0`` to clear.
|
||||
|
||||
Returns:
|
||||
List of Expo push receipt dicts (one per token).
|
||||
"""
|
||||
if not tokens:
|
||||
return []
|
||||
|
||||
results: list[dict[str, Any]] = []
|
||||
|
||||
# Send in batches to stay within Expo's per-request limit.
|
||||
for i in range(0, len(tokens), _EXPO_BATCH_LIMIT):
|
||||
batch = tokens[i : i + _EXPO_BATCH_LIMIT]
|
||||
messages = []
|
||||
for token in batch:
|
||||
msg: dict[str, Any] = {
|
||||
"to": token,
|
||||
"title": title,
|
||||
"body": body,
|
||||
"sound": sound,
|
||||
}
|
||||
if data:
|
||||
msg["data"] = data
|
||||
if badge is not None:
|
||||
msg["badge"] = badge
|
||||
messages.append(msg)
|
||||
|
||||
try:
|
||||
resp = httpx.post(
|
||||
EXPO_PUSH_URL,
|
||||
json=messages,
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
timeout=15,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
payload = resp.json()
|
||||
batch_results = payload.get("data", [])
|
||||
results.extend(batch_results)
|
||||
logger.debug("Expo push batch sent: %d tokens, %d results", len(batch), len(batch_results))
|
||||
except httpx.HTTPStatusError as exc:
|
||||
logger.error("Expo push HTTP error: %s – %s", exc.response.status_code, exc.response.text)
|
||||
except Exception:
|
||||
logger.exception("Expo push notification failed for batch starting at index %d", i)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def send_push_to_owner(
|
||||
owner_id: str,
|
||||
title: str,
|
||||
body: str,
|
||||
data: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
"""Look up all active push tokens for *owner_id* and send them a notification.
|
||||
|
||||
This function is safe to call from Celery task workers. Database errors
|
||||
and push failures are logged but never raised so that the caller task is
|
||||
not retried due to a notification failure.
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
devices = (
|
||||
db.query(MobileDevice)
|
||||
.filter(
|
||||
MobileDevice.owner_id == owner_id,
|
||||
MobileDevice.is_active.is_(True),
|
||||
MobileDevice.push_token.isnot(None),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
tokens = [d.push_token for d in devices if d.push_token]
|
||||
except Exception:
|
||||
logger.exception("Failed to query mobile devices for owner_id=%s", owner_id)
|
||||
return
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
if not tokens:
|
||||
logger.debug("No active push tokens for owner_id=%s", owner_id)
|
||||
return
|
||||
|
||||
logger.info("Sending push notification to %d device(s) for owner_id=%s", len(tokens), owner_id)
|
||||
send_expo_push_notification(tokens=tokens, title=title, body=body, data=data)
|
||||
@@ -2077,6 +2077,78 @@ SETTING_METADATA = {
|
||||
"required": False,
|
||||
"restart_required": True,
|
||||
},
|
||||
"audit_siem_enabled": {
|
||||
"category": "Security",
|
||||
"description": "Enable forwarding of audit events to an external SIEM system (Syslog, Splunk, Logstash, etc.).",
|
||||
"type": "boolean",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
},
|
||||
"audit_siem_transport": {
|
||||
"category": "Security",
|
||||
"description": (
|
||||
"Transport used to forward audit events. 'syslog' sends RFC 5424 messages over UDP/TCP. "
|
||||
"'http' sends JSON POST payloads to a webhook URL (Splunk HEC, Logstash, Grafana Loki, etc.)."
|
||||
),
|
||||
"type": "string",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
"options": ["syslog", "http"],
|
||||
},
|
||||
"audit_siem_syslog_host": {
|
||||
"category": "Security",
|
||||
"description": "Hostname or IP of the syslog receiver.",
|
||||
"type": "string",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
},
|
||||
"audit_siem_syslog_port": {
|
||||
"category": "Security",
|
||||
"description": "Port of the syslog receiver. Default: 514.",
|
||||
"type": "integer",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
},
|
||||
"audit_siem_syslog_protocol": {
|
||||
"category": "Security",
|
||||
"description": "Protocol for syslog transport: 'udp' or 'tcp'. Default: udp.",
|
||||
"type": "string",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
"options": ["udp", "tcp"],
|
||||
},
|
||||
"audit_siem_http_url": {
|
||||
"category": "Security",
|
||||
"description": (
|
||||
"HTTP endpoint URL for SIEM webhook delivery. Supports Splunk HEC, "
|
||||
"Logstash HTTP input, Grafana Loki push API, or any JSON-accepting endpoint."
|
||||
),
|
||||
"type": "string",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
},
|
||||
"audit_siem_http_token": {
|
||||
"category": "Security",
|
||||
"description": "Bearer / HEC token included in the Authorization header of SIEM HTTP requests.",
|
||||
"type": "string",
|
||||
"sensitive": True,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
},
|
||||
"audit_siem_http_custom_headers": {
|
||||
"category": "Security",
|
||||
"description": "Comma-separated 'Key:Value' pairs of extra headers for SIEM HTTP requests.",
|
||||
"type": "string",
|
||||
"sensitive": False,
|
||||
"required": False,
|
||||
"restart_required": False,
|
||||
},
|
||||
# Rate Limiting
|
||||
"rate_limiting_enabled": {
|
||||
"category": "Security",
|
||||
|
||||
@@ -210,6 +210,19 @@ def dispatch_user_notification(
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
# 3. Send push notifications to registered mobile devices
|
||||
try:
|
||||
from app.utils.push_notification import send_push_to_owner
|
||||
|
||||
send_push_to_owner(
|
||||
owner_id=owner_id,
|
||||
title=title,
|
||||
body=message,
|
||||
data={"event_type": event_type, "file_id": file_id},
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Error sending push notification for owner_id=%s event=%s", owner_id, event_type)
|
||||
|
||||
|
||||
def notify_user_document_processed(owner_id: str, filename: str, file_id: int | None = None) -> None:
|
||||
"""Notify a user that their document was successfully processed."""
|
||||
|
||||
@@ -6,6 +6,7 @@ from fastapi import APIRouter
|
||||
|
||||
from app.views.admin_users import router as admin_users_router
|
||||
from app.views.api_tokens import router as api_tokens_router
|
||||
from app.views.audit_logs import router as audit_logs_router
|
||||
from app.views.backup import router as backup_router
|
||||
from app.views.compliance import router as compliance_router
|
||||
from app.views.db_wizard import router as db_wizard_router
|
||||
@@ -61,5 +62,6 @@ router.include_router(imap_accounts_router) # Per-user IMAP ingestion accounts
|
||||
router.include_router(integrations_router) # Unified integrations dashboard
|
||||
router.include_router(notifications_router) # User notification dashboard
|
||||
router.include_router(scheduled_jobs_router) # Admin scheduled batch jobs
|
||||
router.include_router(audit_logs_router) # Comprehensive audit log viewer
|
||||
router.include_router(help_router) # Built-in help / How-To docs
|
||||
router.include_router(compliance_router) # Compliance templates dashboard
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
Audit log viewer UI — admin-only page with filtering and SIEM status.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import Depends, HTTPException, Request, status
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.views.base import APIRouter, get_db, require_login, settings, templates
|
||||
from app.views.settings import require_admin_access
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/admin/audit-logs")
|
||||
@require_login
|
||||
@require_admin_access
|
||||
async def audit_logs_page(request: Request, db: Session = Depends(get_db)):
|
||||
"""Comprehensive audit log viewer with filtering controls.
|
||||
|
||||
Displays a chronological log of all significant actions: logins,
|
||||
document operations, settings changes, and admin actions. The
|
||||
actual data is fetched client-side via the ``/api/audit-logs`` JSON
|
||||
endpoint so that filters, pagination, and live refresh work without
|
||||
full-page reloads.
|
||||
"""
|
||||
try:
|
||||
siem_enabled = settings.audit_siem_enabled
|
||||
siem_transport = settings.audit_siem_transport if siem_enabled else None
|
||||
return templates.TemplateResponse(
|
||||
"audit_logs.html",
|
||||
{
|
||||
"request": request,
|
||||
"app_version": settings.version,
|
||||
"siem_enabled": siem_enabled,
|
||||
"siem_transport": siem_transport,
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Error loading audit logs page: %s", e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to load audit logs page",
|
||||
)
|
||||
@@ -12,6 +12,14 @@ from sqlalchemy.orm import Session # noqa: F401
|
||||
from app.auth import require_login # noqa: F401
|
||||
from app.config import settings
|
||||
from app.database import get_db # noqa: F401
|
||||
from app.utils.i18n import (
|
||||
SUPPORTED_LANGUAGES,
|
||||
detect_language,
|
||||
format_date,
|
||||
format_datetime,
|
||||
format_number,
|
||||
translate,
|
||||
)
|
||||
|
||||
# Set up Jinja2 templates
|
||||
templates_dir = Path(__file__).parent.parent.parent / "frontend" / "templates"
|
||||
@@ -21,6 +29,19 @@ templates = Jinja2Templates(directory=str(templates_dir))
|
||||
templates.env.globals["min"] = min
|
||||
templates.env.globals["max"] = max
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# i18n Jinja2 integration
|
||||
# ---------------------------------------------------------------------------
|
||||
# The _() function is available in every template to translate UI strings.
|
||||
# Usage: {{ _("nav.dashboard") }} or {{ _("upload.max_size", size="10 MB") }}
|
||||
# The locale is automatically resolved from the request context.
|
||||
# A default English implementation is registered as a global so error handlers
|
||||
# that don't go through _inject_global_context still have the function available.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
templates.env.globals["supported_languages"] = SUPPORTED_LANGUAGES
|
||||
templates.env.globals["_"] = lambda key, **kwargs: translate(key, "en", **kwargs)
|
||||
|
||||
# Customize Jinja2Templates to include app_version in all templates
|
||||
original_template_response = templates.TemplateResponse
|
||||
|
||||
@@ -48,8 +69,31 @@ def _inject_global_context(ctx: dict) -> None:
|
||||
session_user = req.session.get("user")
|
||||
# When auth is disabled every visitor is effectively "logged in"
|
||||
ctx.setdefault("is_logged_in", not getattr(settings, "auth_enabled", True) or session_user is not None)
|
||||
|
||||
# --- i18n: detect language and register template helpers ---
|
||||
current_locale = detect_language(req)
|
||||
ctx.setdefault("current_locale", current_locale)
|
||||
|
||||
def _translate(key: str, **kwargs: object) -> str:
|
||||
return translate(key, current_locale, **kwargs)
|
||||
|
||||
def _format_date(value: object, short: bool = False) -> str:
|
||||
return format_date(value, current_locale, short=short) # type: ignore[arg-type]
|
||||
|
||||
def _format_datetime(value: object) -> str:
|
||||
return format_datetime(value, current_locale) # type: ignore[arg-type]
|
||||
|
||||
def _format_number(value: object) -> str:
|
||||
return format_number(value, current_locale) # type: ignore[arg-type]
|
||||
|
||||
ctx.setdefault("_", _translate)
|
||||
ctx.setdefault("format_date_l10n", _format_date)
|
||||
ctx.setdefault("format_datetime_l10n", _format_datetime)
|
||||
ctx.setdefault("format_number_l10n", _format_number)
|
||||
else:
|
||||
ctx.setdefault("is_logged_in", not getattr(settings, "auth_enabled", True))
|
||||
ctx.setdefault("current_locale", "en")
|
||||
ctx.setdefault("_", lambda key, **kw: translate(key, "en", **kw))
|
||||
|
||||
|
||||
def template_response_with_version(*args, **kwargs):
|
||||
|
||||
+1
-2
@@ -3,12 +3,11 @@
|
||||
from fastapi import Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.routing import APIRouter
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from app.auth import require_login
|
||||
from app.views.base import templates
|
||||
|
||||
router = APIRouter()
|
||||
templates = Jinja2Templates(directory="frontend/templates")
|
||||
|
||||
|
||||
@router.get("/admin/plans", response_class=HTMLResponse)
|
||||
|
||||
+188
@@ -2063,3 +2063,191 @@ print(response.json())
|
||||
## Further Assistance
|
||||
|
||||
For additional help with the API, please contact our support team or refer to the [Development Guide](../CONTRIBUTING.md).
|
||||
|
||||
## Mobile App API
|
||||
|
||||
The mobile API provides endpoints used by the native iOS and Android app. All endpoints require authentication (Bearer token or active session cookie).
|
||||
|
||||
For full mobile app documentation see [MobileApp.md](./MobileApp.md).
|
||||
|
||||
### POST /api/mobile/generate-token
|
||||
|
||||
Exchange an active web session for a long-lived API token scoped to the mobile app.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{ "device_name": "John's iPhone" }
|
||||
```
|
||||
|
||||
**Response (201 Created):**
|
||||
```json
|
||||
{
|
||||
"token": "de_AbCdEfGhIjKl...",
|
||||
"token_id": 42,
|
||||
"name": "Mobile App – John's iPhone",
|
||||
"created_at": "2026-03-10T09:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
> The `token` is shown **once only**.
|
||||
|
||||
### POST /api/mobile/register-device
|
||||
|
||||
Register an Expo push token to receive push notifications.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"push_token": "ExponentPushToken[xxxxxx]",
|
||||
"device_name": "John's iPhone",
|
||||
"platform": "ios"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (201 Created):** Device record with `id`, `platform`, `is_active`, `created_at`.
|
||||
|
||||
### GET /api/mobile/devices
|
||||
|
||||
List all registered push-notification devices for the current user.
|
||||
|
||||
**Response (200 OK):** Array of device records.
|
||||
|
||||
### DELETE /api/mobile/devices/{device_id}
|
||||
|
||||
Deactivate a push-notification device. The device will no longer receive push notifications.
|
||||
|
||||
**Response (204 No Content)**
|
||||
|
||||
### GET /api/mobile/whoami
|
||||
|
||||
Return basic profile information for the authenticated user.
|
||||
|
||||
**Response (200 OK):**
|
||||
```json
|
||||
{
|
||||
"owner_id": "john@example.com",
|
||||
"display_name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"avatar_url": "https://www.gravatar.com/avatar/...",
|
||||
"is_admin": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GraphQL API
|
||||
|
||||
DocuElevate exposes a GraphQL API at `/graphql` alongside the REST API. It
|
||||
supports flexible queries with field selection, making it ideal for dashboards
|
||||
and integrations that only need a subset of the available data.
|
||||
|
||||
### Endpoint
|
||||
|
||||
| Method | URL | Description |
|
||||
|--------|-----|-------------|
|
||||
| `POST` | `/graphql` | Execute a GraphQL query or mutation |
|
||||
| `GET` | `/graphql` | Open the GraphiQL interactive playground |
|
||||
|
||||
### Authentication
|
||||
|
||||
The GraphQL endpoint honours the same authentication rules as the REST API:
|
||||
|
||||
- **`AUTH_ENABLED=False`** (default, single-user mode): all queries are
|
||||
allowed without credentials.
|
||||
- **`AUTH_ENABLED=True`** (multi-user mode): a valid session cookie **or**
|
||||
an `Authorization: Bearer <token>` API token is required. Admin-only
|
||||
queries (settings, users) additionally require the `is_admin` flag.
|
||||
|
||||
### Available Queries
|
||||
|
||||
| Field | Returns | Notes |
|
||||
|-------|---------|-------|
|
||||
| `documents(ownerId, limit, offset)` | `[DocumentType]` | Paginated list of documents |
|
||||
| `document(id)` | `DocumentType` | Single document by primary key |
|
||||
| `pipelines(ownerId, limit, offset)` | `[PipelineType]` | Paginated list of pipelines with steps |
|
||||
| `pipeline(id)` | `PipelineType` | Single pipeline by primary key |
|
||||
| `settings(limit, offset)` | `[SettingType]` | Non-sensitive app settings (**admin only**) |
|
||||
| `users(limit, offset)` | `[UserType]` | User profiles (**admin only**) |
|
||||
| `user(userId)` | `UserType` | Single user profile (**admin only**) |
|
||||
|
||||
> **Note:** Sensitive configuration keys (API secrets, passwords, tokens) are
|
||||
> automatically excluded from the `settings` query regardless of the caller's
|
||||
> privilege level.
|
||||
|
||||
### GraphiQL Playground
|
||||
|
||||
Navigate to `http://<your-instance>/graphql` in a browser to open the
|
||||
interactive GraphiQL IDE, which provides schema documentation, auto-complete,
|
||||
and the ability to run queries directly.
|
||||
|
||||
### Example Queries
|
||||
|
||||
**List recent documents:**
|
||||
```graphql
|
||||
{
|
||||
documents(limit: 5) {
|
||||
id
|
||||
originalFilename
|
||||
mimeType
|
||||
fileSize
|
||||
documentTitle
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Fetch a pipeline with its steps:**
|
||||
```graphql
|
||||
{
|
||||
pipeline(id: 1) {
|
||||
id
|
||||
name
|
||||
description
|
||||
isDefault
|
||||
isActive
|
||||
steps {
|
||||
position
|
||||
stepType
|
||||
label
|
||||
enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**List application settings (admin only):**
|
||||
```graphql
|
||||
{
|
||||
settings {
|
||||
key
|
||||
value
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**List user profiles (admin only):**
|
||||
```graphql
|
||||
{
|
||||
users(limit: 10) {
|
||||
userId
|
||||
displayName
|
||||
subscriptionTier
|
||||
isBlocked
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Using variables:**
|
||||
```graphql
|
||||
query GetDocument($id: Int!) {
|
||||
document(id: $id) {
|
||||
id
|
||||
originalFilename
|
||||
documentTitle
|
||||
isDuplicate
|
||||
ocrQualityScore
|
||||
}
|
||||
}
|
||||
```
|
||||
Variables: `{ "id": 42 }`
|
||||
|
||||
@@ -399,6 +399,61 @@ default overage buffer applied across all plans.
|
||||
|
||||
DocuElevate supports HTTP security headers to improve browser-side security. **These headers are disabled by default** since most deployments use a reverse proxy (Traefik, Nginx, etc.) that already adds them. Enable only if deploying directly without a reverse proxy. See [Deployment Guide - Security Headers](DeploymentGuide.md#security-headers) for detailed configuration examples.
|
||||
|
||||
### Audit Logging
|
||||
|
||||
DocuElevate provides comprehensive audit logging that records significant actions (logins, document CRUD, settings changes) to an append-only database table. Every entry captures the timestamp, user, action, resource, client IP, and optional JSON details.
|
||||
|
||||
| **Variable** | **Description** | **Default** |
|
||||
|--------------------------------|---------------------------------------------------------------------------------------------------|-------------|
|
||||
| `AUDIT_LOGGING_ENABLED` | Enable the HTTP request audit-logging middleware. | `true` |
|
||||
| `AUDIT_LOG_INCLUDE_CLIENT_IP` | Include the client IP address in audit log entries. Disable for GDPR-sensitive deployments. | `true` |
|
||||
|
||||
#### SIEM Integration
|
||||
|
||||
Audit events can be forwarded in real time to external SIEM systems for centralised monitoring, alerting, and long-term retention. Two transports are supported:
|
||||
|
||||
* **Syslog** – RFC 5424 structured-data messages over UDP or TCP. Works with rsyslog, syslog-ng, Graylog, Datadog, etc.
|
||||
* **HTTP** – JSON POST payloads compatible with Splunk HEC, Logstash HTTP input, Grafana Loki push API, and any generic webhook.
|
||||
|
||||
| **Variable** | **Description** | **Default** |
|
||||
|-------------------------------------|---------------------------------------------------------------------------------------------------|---------------|
|
||||
| `AUDIT_SIEM_ENABLED` | Enable forwarding of audit events to an external SIEM system. | `false` |
|
||||
| `AUDIT_SIEM_TRANSPORT` | Transport: `syslog` or `http`. | `syslog` |
|
||||
| `AUDIT_SIEM_SYSLOG_HOST` | Hostname or IP of the syslog receiver. | `localhost` |
|
||||
| `AUDIT_SIEM_SYSLOG_PORT` | Port of the syslog receiver. | `514` |
|
||||
| `AUDIT_SIEM_SYSLOG_PROTOCOL` | Protocol for syslog: `udp` or `tcp`. | `udp` |
|
||||
| `AUDIT_SIEM_HTTP_URL` | HTTP endpoint URL for SIEM delivery (e.g. Splunk HEC, Logstash, Loki). | *(empty)* |
|
||||
| `AUDIT_SIEM_HTTP_TOKEN` | Bearer / HEC token for the SIEM HTTP endpoint. | *(empty)* |
|
||||
| `AUDIT_SIEM_HTTP_CUSTOM_HEADERS` | Comma-separated `Key:Value` extra headers for SIEM HTTP requests. | *(empty)* |
|
||||
|
||||
**Example – Syslog to rsyslog:**
|
||||
|
||||
```bash
|
||||
AUDIT_SIEM_ENABLED=true
|
||||
AUDIT_SIEM_TRANSPORT=syslog
|
||||
AUDIT_SIEM_SYSLOG_HOST=syslog.internal.example.com
|
||||
AUDIT_SIEM_SYSLOG_PORT=514
|
||||
AUDIT_SIEM_SYSLOG_PROTOCOL=udp
|
||||
```
|
||||
|
||||
**Example – Splunk HEC:**
|
||||
|
||||
```bash
|
||||
AUDIT_SIEM_ENABLED=true
|
||||
AUDIT_SIEM_TRANSPORT=http
|
||||
AUDIT_SIEM_HTTP_URL=https://splunk.example.com:8088/services/collector/event
|
||||
AUDIT_SIEM_HTTP_TOKEN=your-hec-token
|
||||
```
|
||||
|
||||
**Example – Logstash HTTP input:**
|
||||
|
||||
```bash
|
||||
AUDIT_SIEM_ENABLED=true
|
||||
AUDIT_SIEM_TRANSPORT=http
|
||||
AUDIT_SIEM_HTTP_URL=https://logstash.example.com:8080
|
||||
AUDIT_SIEM_HTTP_TOKEN=
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
DocuElevate implements rate limiting to protect against DoS attacks and API abuse. **Rate limiting is enabled by default** and uses Redis for distributed rate limiting across multiple workers.
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
# Internationalization (i18n) & Localization (l10n) Guide
|
||||
|
||||
DocuElevate supports **10 languages** for its web UI, with automatic browser
|
||||
language detection, user-preference persistence, and an AI-powered fallback
|
||||
translator for strings that haven't been manually translated yet.
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Code | Language | Native Name | Priority |
|
||||
|------|------------|-------------|----------|
|
||||
| `en` | English | English | Tier 1 |
|
||||
| `de` | German | Deutsch | Tier 1 |
|
||||
| `fr` | French | Français | Tier 1 |
|
||||
| `es` | Spanish | Español | Tier 1 |
|
||||
| `it` | Italian | Italiano | Tier 1 |
|
||||
| `pt` | Portuguese | Português | Tier 1 |
|
||||
| `nl` | Dutch | Nederlands | Tier 2 |
|
||||
| `pl` | Polish | Polski | Tier 2 |
|
||||
| `zh` | Chinese | 中文 | Tier 2 |
|
||||
| `ru` | Russian | Русский | Tier 2 |
|
||||
|
||||
> **Tier 1** languages (European priority) have complete, manually-reviewed
|
||||
> translations. **Tier 2** languages have complete translations but may
|
||||
> receive less frequent updates.
|
||||
|
||||
## How Language Is Detected
|
||||
|
||||
DocuElevate resolves the display language in the following priority order:
|
||||
|
||||
1. **User profile preference** — stored in the database (`UserProfile.preferred_language`)
|
||||
and loaded into the session on login
|
||||
2. **Cookie** — `docuelevate_lang` cookie (30-day expiry, set when user selects a language)
|
||||
3. **Browser `Accept-Language` header** — the highest-priority match among supported languages
|
||||
4. **Default** — English (`en`)
|
||||
|
||||
## Selecting Your Language
|
||||
|
||||
### Via the Navigation Bar
|
||||
|
||||
Click the 🌐 **globe icon** in the top navigation bar. A dropdown menu shows all
|
||||
available languages with their native names and flag emoji. The current language
|
||||
is highlighted with a blue checkmark.
|
||||
|
||||
### Via the API
|
||||
|
||||
```bash
|
||||
# Set language to German
|
||||
curl -X POST http://localhost:8000/api/i18n/language \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"language": "de"}'
|
||||
|
||||
# List all available languages
|
||||
curl http://localhost:8000/api/i18n/languages
|
||||
```
|
||||
|
||||
### Via Cookie (Programmatic)
|
||||
|
||||
Set the `docuelevate_lang` cookie to any supported language code:
|
||||
|
||||
```javascript
|
||||
document.cookie = "docuelevate_lang=fr; max-age=2592000; path=/";
|
||||
location.reload();
|
||||
```
|
||||
|
||||
## For Developers
|
||||
|
||||
### Translation File Structure
|
||||
|
||||
Translations are stored as flat JSON files in `frontend/translations/`:
|
||||
|
||||
```
|
||||
frontend/translations/
|
||||
├── en.json # English (base / reference)
|
||||
├── de.json # German
|
||||
├── fr.json # French
|
||||
├── es.json # Spanish
|
||||
├── it.json # Italian
|
||||
├── pt.json # Portuguese
|
||||
├── nl.json # Dutch
|
||||
├── pl.json # Polish
|
||||
├── zh.json # Chinese
|
||||
└── ru.json # Russian
|
||||
```
|
||||
|
||||
Each file is a flat key-value dictionary with dot-notation namespacing:
|
||||
|
||||
```json
|
||||
{
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.upload": "Upload",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"footer.copyright": "DocuElevate {year}"
|
||||
}
|
||||
```
|
||||
|
||||
### Using Translations in Templates
|
||||
|
||||
The `_()` function is available globally in all Jinja2 templates:
|
||||
|
||||
```jinja2
|
||||
{# Simple translation #}
|
||||
<h1>{{ _("dashboard.title") }}</h1>
|
||||
|
||||
{# Translation with placeholders #}
|
||||
<p>{{ _("upload.max_size", size="50 MB") }}</p>
|
||||
|
||||
{# Translation in attributes #}
|
||||
<button aria-label="{{ _('common.save') }}">{{ _("common.save") }}</button>
|
||||
```
|
||||
|
||||
### Using Translations in Python
|
||||
|
||||
```python
|
||||
from app.utils.i18n import translate
|
||||
|
||||
# Basic translation
|
||||
text = translate("nav.dashboard", "de") # → "Übersicht"
|
||||
|
||||
# With placeholders
|
||||
text = translate("footer.copyright", "fr", year="2025") # → "DocuElevate 2025"
|
||||
```
|
||||
|
||||
### Localization Helpers
|
||||
|
||||
Format dates, times, and numbers according to locale conventions:
|
||||
|
||||
```jinja2
|
||||
{# In templates — locale is automatically detected #}
|
||||
<span>{{ format_date_l10n(document.created_at) }}</span>
|
||||
<span>{{ format_number_l10n(file_count) }}</span>
|
||||
```
|
||||
|
||||
```python
|
||||
# In Python
|
||||
from app.utils.i18n import format_date, format_number
|
||||
|
||||
format_date(date(2025, 3, 15), "de") # → "15. March 2025"
|
||||
format_date(date(2025, 3, 15), "de", short=True) # → "15.03.2025"
|
||||
format_number(1234567, "de") # → "1.234.567"
|
||||
format_number(1234.56, "en") # → "1,234.56"
|
||||
```
|
||||
|
||||
### Adding a New Translation Key
|
||||
|
||||
1. Add the key and English text to `frontend/translations/en.json`
|
||||
2. Add translations for all other languages in their respective files
|
||||
3. Use `{{ _("your.new.key") }}` in templates
|
||||
|
||||
### AI Fallback Translation
|
||||
|
||||
When a translation key exists in English but not in the target language,
|
||||
DocuElevate can use the configured AI provider (OpenAI, Anthropic, etc.)
|
||||
to translate the string on-the-fly:
|
||||
|
||||
```python
|
||||
from app.utils.i18n import translate_with_ai_fallback
|
||||
|
||||
# Falls back to AI if no manual translation exists
|
||||
translated = translate_with_ai_fallback("Welcome to our platform", "de")
|
||||
```
|
||||
|
||||
The AI fallback:
|
||||
- Uses the `AI_MODEL` or `OPENAI_MODEL` setting
|
||||
- Caches results in memory for the process lifetime
|
||||
- Returns the original English text if the AI call fails
|
||||
- Is designed for graceful degradation — the UI never breaks
|
||||
|
||||
### Adding a New Language
|
||||
|
||||
1. Create a new JSON file in `frontend/translations/` (e.g., `ja.json`)
|
||||
2. Copy the structure from `en.json` and translate all values
|
||||
3. Add the language to `SUPPORTED_LANGUAGES` in `app/utils/i18n.py`:
|
||||
```python
|
||||
{"code": "ja", "name": "Japanese", "native": "日本語", "flag": "🇯🇵"},
|
||||
```
|
||||
4. Add locale formatting rules to `_LOCALE_FORMATS` in the same file
|
||||
5. Create a database migration if needed (the `preferred_language` column
|
||||
already accepts any string up to 10 characters)
|
||||
|
||||
### Database Migration
|
||||
|
||||
Migration `027_add_user_language_preference` adds a `preferred_language`
|
||||
column to the `user_profiles` table. This column stores the user's chosen
|
||||
UI language as an ISO 639-1 code (e.g., `"de"`, `"fr"`). A `NULL` value
|
||||
means "auto-detect from browser settings."
|
||||
|
||||
### API Reference
|
||||
|
||||
#### `GET /api/i18n/languages`
|
||||
|
||||
Returns all supported languages and the current active language.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"languages": [
|
||||
{"code": "en", "name": "English", "native": "English", "flag": "🇬🇧"},
|
||||
{"code": "de", "name": "German", "native": "Deutsch", "flag": "🇩🇪"}
|
||||
],
|
||||
"current": "en",
|
||||
"default": "en"
|
||||
}
|
||||
```
|
||||
|
||||
#### `POST /api/i18n/language`
|
||||
|
||||
Set the preferred UI language. Persists in session, cookie, and database.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{"language": "de"}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"language": "de",
|
||||
"message": "Language changed to Deutsch"
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
No additional configuration is required. The i18n system works out of the box
|
||||
with the default English language and automatically detects browser preferences.
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| Browser `Accept-Language` | Auto-detected | Used when no explicit preference is set |
|
||||
| `docuelevate_lang` cookie | Not set | Set when user selects a language via the UI |
|
||||
| `UserProfile.preferred_language` | `NULL` | Stored in DB for authenticated users |
|
||||
@@ -0,0 +1,252 @@
|
||||
# Mobile App
|
||||
|
||||
DocuElevate includes a native mobile application for iOS and Android built with **React Native** and **Expo**. The app allows users to capture documents with the device camera, pick files from the device storage, and receive push notifications when documents finish processing.
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | iOS | Android |
|
||||
|---------|-----|---------|
|
||||
| SSO login (OAuth2) | ✅ | ✅ |
|
||||
| Local / basic auth login | ✅ | ✅ |
|
||||
| Auto-generated API token | ✅ | ✅ |
|
||||
| Camera capture → upload | ✅ | ✅ |
|
||||
| File picker upload | ✅ | ✅ |
|
||||
| Share Sheet / Share Intent | ✅ | ✅ |
|
||||
| Push notifications | ✅ | ✅ |
|
||||
| Document list | ✅ | ✅ |
|
||||
| Dark mode | ✅ | ✅ |
|
||||
|
||||
## Getting Started (Development)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18 or later
|
||||
- [Expo CLI](https://docs.expo.dev/get-started/installation/): `npm install -g @expo/cli`
|
||||
- [Expo Go](https://expo.dev/client) app on your iOS or Android device (for development)
|
||||
- A running DocuElevate server reachable from your device
|
||||
|
||||
### Run in development mode
|
||||
|
||||
```bash
|
||||
cd mobile
|
||||
npm install
|
||||
npx expo start
|
||||
```
|
||||
|
||||
Scan the QR code with **Expo Go** on your device. On iOS you can also use the Camera app.
|
||||
|
||||
## Building for Production
|
||||
|
||||
DocuElevate uses **Expo Application Services (EAS)** to produce App Store / Play Store binaries.
|
||||
|
||||
```bash
|
||||
# Install EAS CLI globally
|
||||
npm install -g eas-cli
|
||||
|
||||
# Authenticate with Expo
|
||||
eas login
|
||||
|
||||
# Build for iOS (requires Apple Developer account)
|
||||
eas build --platform ios
|
||||
|
||||
# Build for Android
|
||||
eas build --platform android
|
||||
```
|
||||
|
||||
See the [EAS Build documentation](https://docs.expo.dev/build/introduction/) for full setup instructions.
|
||||
|
||||
## Authentication
|
||||
|
||||
### SSO Login Flow
|
||||
|
||||
The mobile app uses the server's existing OAuth2/SSO setup:
|
||||
|
||||
1. User enters the DocuElevate server URL on the login screen.
|
||||
2. The app opens `<server>/login?mobile=1&redirect_uri=docuelevate://callback` in the **system browser** (Safari / Chrome).
|
||||
3. The user authenticates via SSO or local credentials.
|
||||
4. The server redirects back to `docuelevate://callback`.
|
||||
5. The app calls `POST /api/mobile/generate-token` to exchange the session for a **long-lived API token**.
|
||||
6. The token is stored securely in the device's keychain (`expo-secure-store`).
|
||||
|
||||
### Auto-generated Mobile Token
|
||||
|
||||
When the mobile app completes login it automatically creates a named API token (`"Mobile App – <device name>"`) via `POST /api/mobile/generate-token`. This token:
|
||||
|
||||
- Works identically to tokens created manually in the web UI.
|
||||
- Is shown in the **API Tokens** page (`/api-tokens`) and can be revoked there.
|
||||
- Is stored in the device's secure keychain, never in plain storage.
|
||||
|
||||
## Push Notifications
|
||||
|
||||
Push notifications are delivered via the **Expo Push Notification** service, which routes through Apple Push Notification service (APNs) for iOS and Firebase Cloud Messaging (FCM) for Android.
|
||||
|
||||
**No server-side APNs/FCM credentials are required** – Expo's servers handle the provider integration.
|
||||
|
||||
### How it works
|
||||
|
||||
1. After login, the app requests notification permission from the operating system.
|
||||
2. If granted, the app obtains an **Expo Push Token** (`ExponentPushToken[…]`).
|
||||
3. The token is registered with the backend via `POST /api/mobile/register-device`.
|
||||
4. When a document finishes processing, the server sends a push notification to all registered devices for that user.
|
||||
|
||||
### Managing registered devices
|
||||
|
||||
Users can see and remove their registered devices from the **Profile** tab in the app, or via the API:
|
||||
|
||||
```bash
|
||||
# List registered devices
|
||||
curl -H "Authorization: Bearer <token>" https://your-server/api/mobile/devices
|
||||
|
||||
# Remove a device
|
||||
curl -X DELETE -H "Authorization: Bearer <token>" https://your-server/api/mobile/devices/<id>
|
||||
```
|
||||
|
||||
## Uploading Documents
|
||||
|
||||
### Camera Capture
|
||||
|
||||
1. Open the **Upload** tab.
|
||||
2. Tap **Camera**.
|
||||
3. Point the camera at the document and take a photo.
|
||||
4. The image is immediately uploaded and queued for processing.
|
||||
|
||||
### File Picker
|
||||
|
||||
1. Open the **Upload** tab.
|
||||
2. Tap **File Picker**.
|
||||
3. Browse to and select one or more files (PDF, DOCX, images, etc.).
|
||||
4. Files are uploaded and queued for processing.
|
||||
|
||||
### Share Sheet (iOS) / Share Intent (Android)
|
||||
|
||||
The app registers itself as a share target so any file can be sent directly to DocuElevate from another app:
|
||||
|
||||
1. Open a file in Files, Mail, Safari, or any other app.
|
||||
2. Tap the **Share** button (iOS) or **Share** (Android).
|
||||
3. Find and tap **DocuElevate** in the share sheet.
|
||||
4. The file is immediately uploaded.
|
||||
|
||||
> **Note:** The app must be installed on the device for it to appear in the share sheet.
|
||||
|
||||
## Mobile API Endpoints
|
||||
|
||||
The backend exposes a dedicated `/api/mobile/` namespace:
|
||||
|
||||
| Method | Endpoint | Auth | Description |
|
||||
|--------|----------|------|-------------|
|
||||
| `POST` | `/api/mobile/generate-token` | Session | Exchange SSO session for API token |
|
||||
| `POST` | `/api/mobile/register-device` | Bearer | Register Expo push token |
|
||||
| `GET` | `/api/mobile/devices` | Bearer | List registered devices |
|
||||
| `DELETE` | `/api/mobile/devices/{id}` | Bearer | Deactivate a device |
|
||||
| `GET` | `/api/mobile/whoami` | Bearer | Get current user profile |
|
||||
|
||||
All other API endpoints (file upload, file listing, etc.) work with Bearer token authentication.
|
||||
|
||||
### POST /api/mobile/generate-token
|
||||
|
||||
Exchanges an active web session (cookie) for a permanent API token suitable for use in the mobile app.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{ "device_name": "John's iPhone" }
|
||||
```
|
||||
|
||||
**Response (201):**
|
||||
```json
|
||||
{
|
||||
"token": "de_AbCdEfGhIjKl...",
|
||||
"token_id": 42,
|
||||
"name": "Mobile App – John's iPhone",
|
||||
"created_at": "2026-03-10T09:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
> ⚠️ The `token` value is returned **once only**. Store it in the device's secure keychain immediately.
|
||||
|
||||
### POST /api/mobile/register-device
|
||||
|
||||
Registers an Expo push token for the authenticated user.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"push_token": "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
|
||||
"device_name": "John's iPhone",
|
||||
"platform": "ios"
|
||||
}
|
||||
```
|
||||
|
||||
Supported platforms: `ios`, `android`, `web`.
|
||||
|
||||
Re-registering the same token is safe (idempotent).
|
||||
|
||||
### GET /api/mobile/whoami
|
||||
|
||||
Returns the current user's profile.
|
||||
|
||||
**Response (200):**
|
||||
```json
|
||||
{
|
||||
"owner_id": "john@example.com",
|
||||
"display_name": "John Doe",
|
||||
"email": "john@example.com",
|
||||
"avatar_url": "https://www.gravatar.com/avatar/...",
|
||||
"is_admin": false
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
No server-side configuration is required to enable the mobile app. The Expo push notification routing does not need FCM or APNs credentials on the server.
|
||||
|
||||
If you wish to use **direct FCM/APNs** without Expo's relay, replace the `send_expo_push_notification` function in `app/utils/push_notification.py` with your own implementation.
|
||||
|
||||
## Project Structure (mobile/)
|
||||
|
||||
```
|
||||
mobile/
|
||||
├── App.tsx # Root component
|
||||
├── app.json # Expo/EAS configuration
|
||||
├── eas.json # EAS Build profiles
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── src/
|
||||
├── context/
|
||||
│ └── AuthContext.tsx # Auth state + SSO login flow
|
||||
├── hooks/
|
||||
│ └── usePushNotifications.ts # Push token registration
|
||||
├── screens/
|
||||
│ ├── LoginScreen.tsx # Server URL + SSO button
|
||||
│ ├── UploadScreen.tsx # Camera capture + file picker
|
||||
│ ├── FilesScreen.tsx # Processed document list
|
||||
│ └── ProfileScreen.tsx # User profile + sign out
|
||||
└── services/
|
||||
└── api.ts # DocuElevate REST API client
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Authentication was cancelled or failed"
|
||||
|
||||
- Ensure the server URL is correct (including `https://`).
|
||||
- Verify the server is reachable from your device's network.
|
||||
- Confirm that `AUTH_ENABLED=True` on the server.
|
||||
|
||||
### Push notifications not arriving
|
||||
|
||||
1. Check that the app has notification permission (Settings → DocuElevate → Notifications).
|
||||
2. Verify the device is registered: `GET /api/mobile/devices`.
|
||||
3. Ensure the server can reach `https://exp.host` (outbound HTTPS on port 443).
|
||||
4. On Android, add `google-services.json` to the `mobile/` directory if you are building your own binary.
|
||||
|
||||
### "Connection refused" or timeout
|
||||
|
||||
- Verify that the DocuElevate server is running and accessible.
|
||||
- Ensure the server's `EXTERNAL_HOSTNAME` or reverse proxy is configured correctly.
|
||||
- Check that the server accepts CORS requests from `docuelevate://`.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [API Documentation](./API.md)
|
||||
- [Configuration Guide](./ConfigurationGuide.md)
|
||||
- [Deployment Guide](./DeploymentGuide.md)
|
||||
@@ -0,0 +1,222 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Audit Logs - DocuElevate{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div x-data="auditLogs()" x-init="fetchLogs()" class="container mx-auto px-4 py-8 max-w-7xl">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
|
||||
<i class="fas fa-shield-halved mr-2 text-indigo-600" aria-hidden="true"></i>Audit Logs
|
||||
</h1>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">
|
||||
Comprehensive, append-only record of all significant actions.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-3 md:mt-0 flex items-center gap-3">
|
||||
{% if siem_enabled %}
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100"
|
||||
title="Events are being forwarded to {{ siem_transport|upper }}">
|
||||
<i class="fas fa-tower-broadcast mr-1" aria-hidden="true"></i>SIEM: {{ siem_transport|upper }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
title="SIEM forwarding is disabled">
|
||||
<i class="fas fa-tower-broadcast mr-1" aria-hidden="true"></i>SIEM: Off
|
||||
</span>
|
||||
{% endif %}
|
||||
<button @click="fetchLogs()" class="inline-flex items-center px-3 py-1.5 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-200 dark:border-gray-600 dark:hover:bg-gray-600 min-h-[44px] min-w-[44px]"
|
||||
aria-label="Refresh audit logs">
|
||||
<i class="fas fa-arrows-rotate mr-1" aria-hidden="true"></i>Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<section class="bg-white dark:bg-gray-800 shadow rounded-lg p-4 mb-6" aria-label="Audit log filters">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div>
|
||||
<label for="filter-action" class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Action</label>
|
||||
<select id="filter-action" x-model="filters.action" @change="fetchLogs()"
|
||||
class="w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white text-sm">
|
||||
<option value="">All actions</option>
|
||||
<template x-for="a in distinctActions" :key="a">
|
||||
<option :value="a" x-text="a"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="filter-user" class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">User</label>
|
||||
<select id="filter-user" x-model="filters.user" @change="fetchLogs()"
|
||||
class="w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white text-sm">
|
||||
<option value="">All users</option>
|
||||
<template x-for="u in distinctUsers" :key="u">
|
||||
<option :value="u" x-text="u"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="filter-severity" class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Severity</label>
|
||||
<select id="filter-severity" x-model="filters.severity" @change="fetchLogs()"
|
||||
class="w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white text-sm">
|
||||
<option value="">All</option>
|
||||
<option value="info">Info</option>
|
||||
<option value="warning">Warning</option>
|
||||
<option value="error">Error</option>
|
||||
<option value="critical">Critical</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="filter-resource" class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Resource Type</label>
|
||||
<input id="filter-resource" type="text" x-model.debounce.300ms="filters.resource_type" @input="fetchLogs()"
|
||||
placeholder="e.g. document, user"
|
||||
class="w-full rounded-md border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white text-sm min-h-[44px]">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Results summary -->
|
||||
<div class="flex items-center justify-between mb-3 text-sm text-gray-500 dark:text-gray-400" aria-live="polite">
|
||||
<span x-show="!loading" x-text="total + ' event' + (total !== 1 ? 's' : '') + ' found'"></span>
|
||||
<span x-show="loading"><i class="fas fa-spinner fa-spin mr-1" aria-hidden="true"></i>Loading…</span>
|
||||
</div>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700" aria-label="Audit log events">
|
||||
<thead class="bg-gray-50 dark:bg-gray-700">
|
||||
<tr>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Timestamp</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Severity</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">User</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Action</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Resource</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">IP</th>
|
||||
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider">Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<template x-for="e in entries" :key="e.id">
|
||||
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50">
|
||||
<td class="px-4 py-2 whitespace-nowrap text-xs text-gray-600 dark:text-gray-300" x-text="formatTs(e.timestamp)"></td>
|
||||
<td class="px-4 py-2 whitespace-nowrap text-xs">
|
||||
<span :class="severityClass(e.severity)" class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium" x-text="e.severity"></span>
|
||||
</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap text-xs text-gray-700 dark:text-gray-200" x-text="e.user"></td>
|
||||
<td class="px-4 py-2 whitespace-nowrap text-xs font-mono text-indigo-700 dark:text-indigo-300" x-text="e.action"></td>
|
||||
<td class="px-4 py-2 whitespace-nowrap text-xs text-gray-600 dark:text-gray-300">
|
||||
<span x-text="e.resource_type || '—'"></span>
|
||||
<span x-show="e.resource_id" class="text-gray-400" x-text="' #' + e.resource_id"></span>
|
||||
</td>
|
||||
<td class="px-4 py-2 whitespace-nowrap text-xs text-gray-500 dark:text-gray-400" x-text="e.ip_address || '—'"></td>
|
||||
<td class="px-4 py-2 text-xs text-gray-500 dark:text-gray-400 max-w-xs truncate" :title="e.details ? JSON.stringify(e.details) : ''" x-text="e.details ? JSON.stringify(e.details) : '—'"></td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr x-show="!loading && entries.length === 0">
|
||||
<td colspan="7" class="px-4 py-8 text-center text-gray-400 dark:text-gray-500">
|
||||
<i class="fas fa-inbox text-3xl mb-2" aria-hidden="true"></i>
|
||||
<p class="text-lg">No audit events recorded yet.</p>
|
||||
<p class="text-sm mt-1">Significant actions (logins, document operations, settings changes) will appear here.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav class="flex items-center justify-between mt-4" aria-label="Audit log pagination" x-show="total > filters.limit">
|
||||
<button @click="prevPage()" :disabled="filters.offset === 0"
|
||||
class="px-3 py-1.5 rounded-md text-sm border border-gray-300 dark:border-gray-600 disabled:opacity-50 min-h-[44px] min-w-[44px]"
|
||||
aria-label="Previous page">
|
||||
<i class="fas fa-chevron-left mr-1" aria-hidden="true"></i>Prev
|
||||
</button>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400" x-text="'Page ' + currentPage + ' of ' + totalPages"></span>
|
||||
<button @click="nextPage()" :disabled="filters.offset + filters.limit >= total"
|
||||
class="px-3 py-1.5 rounded-md text-sm border border-gray-300 dark:border-gray-600 disabled:opacity-50 min-h-[44px] min-w-[44px]"
|
||||
aria-label="Next page">
|
||||
Next<i class="fas fa-chevron-right ml-1" aria-hidden="true"></i>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function auditLogs() {
|
||||
return {
|
||||
entries: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
distinctActions: [],
|
||||
distinctUsers: [],
|
||||
filters: {
|
||||
action: '',
|
||||
user: '',
|
||||
severity: '',
|
||||
resource_type: '',
|
||||
limit: 50,
|
||||
offset: 0,
|
||||
},
|
||||
get currentPage() { return Math.floor(this.filters.offset / this.filters.limit) + 1; },
|
||||
get totalPages() { return Math.max(1, Math.ceil(this.total / this.filters.limit)); },
|
||||
|
||||
async fetchLogs() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
if (this.filters.action) params.set('action', this.filters.action);
|
||||
if (this.filters.user) params.set('user', this.filters.user);
|
||||
if (this.filters.severity) params.set('severity', this.filters.severity);
|
||||
if (this.filters.resource_type) params.set('resource_type', this.filters.resource_type);
|
||||
params.set('limit', this.filters.limit);
|
||||
params.set('offset', this.filters.offset);
|
||||
|
||||
const [logsResp, actionsResp, usersResp] = await Promise.all([
|
||||
fetch('/api/audit-logs?' + params.toString()),
|
||||
fetch('/api/audit-logs/actions'),
|
||||
fetch('/api/audit-logs/users'),
|
||||
]);
|
||||
if (logsResp.ok) {
|
||||
const data = await logsResp.json();
|
||||
this.entries = data.items;
|
||||
this.total = data.total;
|
||||
}
|
||||
if (actionsResp.ok) this.distinctActions = await actionsResp.json();
|
||||
if (usersResp.ok) this.distinctUsers = await usersResp.json();
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
prevPage() {
|
||||
if (this.filters.offset > 0) {
|
||||
this.filters.offset = Math.max(0, this.filters.offset - this.filters.limit);
|
||||
this.fetchLogs();
|
||||
}
|
||||
},
|
||||
nextPage() {
|
||||
if (this.filters.offset + this.filters.limit < this.total) {
|
||||
this.filters.offset += this.filters.limit;
|
||||
this.fetchLogs();
|
||||
}
|
||||
},
|
||||
formatTs(iso) {
|
||||
if (!iso) return '—';
|
||||
const d = new Date(iso);
|
||||
return d.toLocaleString();
|
||||
},
|
||||
severityClass(sev) {
|
||||
const map = {
|
||||
info: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
|
||||
warning: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200',
|
||||
error: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200',
|
||||
critical: 'bg-red-200 text-red-900 dark:bg-red-800 dark:text-red-100',
|
||||
};
|
||||
return map[sev] || 'bg-gray-100 text-gray-800';
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
+146
-76
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-color-scheme-default="{{ ui_default_color_scheme | default('system') }}">
|
||||
<html lang="{{ current_locale | default('en') }}" data-color-scheme-default="{{ ui_default_color_scheme | default('system') }}">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>{% block title %}DocuElevate{% endblock %}</title>
|
||||
@@ -37,10 +37,10 @@
|
||||
data-multi-user="{{ 'true' if multi_user_enabled else 'false' }}"
|
||||
data-allow-signup="{{ 'true' if allow_signup else 'false' }}">
|
||||
<!-- Skip to main content link for keyboard/screen reader users -->
|
||||
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||||
<a href="#main-content" class="skip-link">{{ _("nav.skip_to_content") }}</a>
|
||||
|
||||
<!-- Global Nav -->
|
||||
<nav class="bg-white shadow relative" aria-label="Main navigation">
|
||||
<nav class="bg-white shadow relative" aria-label="{{ _('nav.main_navigation') }}">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex justify-between h-16 items-center">
|
||||
|
||||
<!-- Brand + Icon -->
|
||||
@@ -70,12 +70,12 @@
|
||||
<a href="/pricing"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/pricing' %}aria-current="page"{% endif %}>
|
||||
Pricing
|
||||
{{ _("nav.pricing") }}
|
||||
</a>
|
||||
<a href="/about"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/about' %}aria-current="page"{% endif %}>
|
||||
About
|
||||
{{ _("nav.about") }}
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
@@ -84,32 +84,32 @@
|
||||
<a href="/"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-home mr-1 text-gray-400" aria-hidden="true"></i>Dashboard
|
||||
<i class="fas fa-home mr-1 text-gray-400" aria-hidden="true"></i>{{ _("nav.dashboard") }}
|
||||
</a>
|
||||
<a href="/upload"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-blue-600 hover:text-blue-800 hover:bg-blue-50"
|
||||
{% if request and request.url.path == '/upload' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-upload mr-1" aria-hidden="true"></i>Upload
|
||||
<i class="fas fa-upload mr-1" aria-hidden="true"></i>{{ _("nav.upload") }}
|
||||
</a>
|
||||
<a href="/files"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/files' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-folder-open mr-1 text-gray-400" aria-hidden="true"></i>Files
|
||||
<i class="fas fa-folder-open mr-1 text-gray-400" aria-hidden="true"></i>{{ _("nav.files") }}
|
||||
</a>
|
||||
<a href="/search"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/search' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-search mr-1 text-gray-400" aria-hidden="true"></i>Search
|
||||
<i class="fas fa-search mr-1 text-gray-400" aria-hidden="true"></i>{{ _("nav.search") }}
|
||||
</a>
|
||||
<a href="/pipelines"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/pipelines' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-project-diagram mr-1 text-gray-400" aria-hidden="true"></i>Pipelines
|
||||
<i class="fas fa-project-diagram mr-1 text-gray-400" aria-hidden="true"></i>{{ _("nav.pipelines") }}
|
||||
</a>
|
||||
<a href="/integrations"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/integrations' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-plug mr-1 text-gray-400" aria-hidden="true"></i>Integrations
|
||||
<i class="fas fa-plug mr-1 text-gray-400" aria-hidden="true"></i>{{ _("nav.integrations") }}
|
||||
</a>
|
||||
|
||||
<!-- Admin dropdown – shown only for admin users via JS -->
|
||||
@@ -124,7 +124,7 @@
|
||||
:aria-expanded="adminMenuOpen"
|
||||
>
|
||||
<i class="fas fa-shield-alt mr-1 text-red-500" aria-hidden="true"></i>
|
||||
Admin
|
||||
{{ _("nav.admin") }}
|
||||
<i class="fas fa-chevron-down ml-1 text-xs" aria-hidden="true"></i>
|
||||
</button>
|
||||
<div
|
||||
@@ -141,49 +141,55 @@
|
||||
>
|
||||
<div class="py-1">
|
||||
<a href="/settings" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-cog w-4 mr-2 text-gray-500" aria-hidden="true"></i> Settings
|
||||
<i class="fas fa-cog w-4 mr-2 text-gray-500" aria-hidden="true"></i> {{ _("nav.settings") }}
|
||||
</a>
|
||||
<a href="/admin/users" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-users w-4 mr-2 text-blue-500" aria-hidden="true"></i> Users
|
||||
<i class="fas fa-users w-4 mr-2 text-blue-500" aria-hidden="true"></i> {{ _("nav.users") }}
|
||||
</a>
|
||||
<a href="/admin/plans" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-layer-group w-4 mr-2 text-indigo-500" aria-hidden="true"></i> Plan Designer
|
||||
<i class="fas fa-layer-group w-4 mr-2 text-indigo-500" aria-hidden="true"></i> {{ _("nav.plan_designer") }}
|
||||
</a>
|
||||
<a href="/admin/credentials" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-key w-4 mr-2 text-yellow-500" aria-hidden="true"></i> Credentials
|
||||
<i class="fas fa-key w-4 mr-2 text-yellow-500" aria-hidden="true"></i> {{ _("nav.credentials") }}
|
||||
</a>
|
||||
<a href="/admin/files" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-folder-open w-4 mr-2 text-gray-500" aria-hidden="true"></i> File Manager
|
||||
<i class="fas fa-folder-open w-4 mr-2 text-gray-500" aria-hidden="true"></i> {{ _("nav.file_manager") }}
|
||||
</a>
|
||||
<div class="border-t border-gray-100 my-1"></div>
|
||||
<a href="/duplicates" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-clone w-4 mr-2 text-orange-500" aria-hidden="true"></i> Duplicates
|
||||
<i class="fas fa-clone w-4 mr-2 text-orange-500" aria-hidden="true"></i> {{ _("nav.duplicates") }}
|
||||
</a>
|
||||
<a href="/similarity" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-sitemap w-4 mr-2 text-purple-500" aria-hidden="true"></i> Similarity
|
||||
<i class="fas fa-sitemap w-4 mr-2 text-purple-500" aria-hidden="true"></i> {{ _("nav.similarity") }}
|
||||
</a>
|
||||
<a href="/admin/queue" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-stream w-4 mr-2 text-blue-500" aria-hidden="true"></i> Queue Monitor
|
||||
<i class="fas fa-stream w-4 mr-2 text-blue-500" aria-hidden="true"></i> {{ _("nav.queue_monitor") }}
|
||||
</a>
|
||||
<a href="/admin/scheduled-jobs" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-clock w-4 mr-2 text-indigo-500" aria-hidden="true"></i> Scheduled Jobs
|
||||
<i class="fas fa-clock w-4 mr-2 text-indigo-500" aria-hidden="true"></i> {{ _("nav.scheduled_jobs") }}
|
||||
</a>
|
||||
<a href="/admin/compliance" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-check-double w-4 mr-2 text-green-500" aria-hidden="true"></i> Compliance
|
||||
</a>
|
||||
<a href="/admin/backup" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-database w-4 mr-2 text-green-600" aria-hidden="true"></i> Backup & Restore
|
||||
<i class="fas fa-database w-4 mr-2 text-green-600" aria-hidden="true"></i> {{ _("nav.backup_restore") }}
|
||||
</a>
|
||||
<a href="/admin/audit-logs" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-shield-halved w-4 mr-2 text-indigo-500" aria-hidden="true"></i> Audit Logs
|
||||
</a>
|
||||
<a href="/admin/audit-logs" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-shield-halved w-4 mr-2 text-indigo-500" aria-hidden="true"></i> Audit Logs
|
||||
</a>
|
||||
<a href="/status" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
||||
{% if request and request.url.path == '/status' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-dot w-4 mr-2 text-gray-500" aria-hidden="true"></i> Status
|
||||
<i class="fas fa-circle-dot w-4 mr-2 text-gray-500" aria-hidden="true"></i> {{ _("nav.status") }}
|
||||
</a>
|
||||
<div class="border-t border-gray-100 my-1"></div>
|
||||
<a href="/admin/api-docs" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-code w-4 mr-2 text-teal-500" aria-hidden="true"></i> API Docs
|
||||
<i class="fas fa-code w-4 mr-2 text-teal-500" aria-hidden="true"></i> {{ _("nav.api_docs") }}
|
||||
</a>
|
||||
<a href="/developer-docs/" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-book w-4 mr-2 text-teal-500" aria-hidden="true"></i> Developer Docs
|
||||
<i class="fas fa-book w-4 mr-2 text-teal-500" aria-hidden="true"></i> {{ _("nav.developer_docs") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -194,18 +200,18 @@
|
||||
<!-- Help – always visible, for every visitor regardless of auth state -->
|
||||
<a href="/help"
|
||||
class="px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-100"
|
||||
aria-label="Help Center"
|
||||
title="Help Center"
|
||||
aria-label="{{ _('nav.help_center') }}"
|
||||
title="{{ _('nav.help_center') }}"
|
||||
{% if request and request.url.path == '/help' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-question mr-1 text-gray-400" aria-hidden="true"></i>Help
|
||||
<i class="fas fa-circle-question mr-1 text-gray-400" aria-hidden="true"></i>{{ _("nav.help") }}
|
||||
</a>
|
||||
|
||||
<!-- Bell notification icon -->
|
||||
<a href="/notifications"
|
||||
id="notificationBell"
|
||||
class="relative p-1.5 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500"
|
||||
aria-label="Notifications"
|
||||
title="Notifications"
|
||||
aria-label="{{ _('nav.notifications') }}"
|
||||
title="{{ _('nav.notifications') }}"
|
||||
{% if request and request.url.path == '/notifications' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-bell" aria-hidden="true"></i>
|
||||
<span id="notificationBadge"
|
||||
@@ -213,14 +219,59 @@
|
||||
aria-live="polite"></span>
|
||||
</a>
|
||||
|
||||
<!-- Language selector dropdown -->
|
||||
<div x-data="{ langOpen: false }" class="relative">
|
||||
<button
|
||||
@click="langOpen = !langOpen"
|
||||
@click.outside="langOpen = false"
|
||||
type="button"
|
||||
class="p-1.5 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500"
|
||||
aria-label="{{ _('language.selector') }}"
|
||||
title="{{ _('language.selector') }}"
|
||||
:aria-expanded="langOpen"
|
||||
aria-haspopup="true"
|
||||
>
|
||||
<i class="fas fa-globe"></i>
|
||||
</button>
|
||||
<div
|
||||
x-show="langOpen"
|
||||
x-transition:enter="transition ease-out duration-100 transform"
|
||||
x-transition:enter-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
x-transition:leave="transition ease-in duration-75 transform"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 z-50"
|
||||
role="menu"
|
||||
aria-label="{{ _('language.selector') }}"
|
||||
>
|
||||
<div class="py-1">
|
||||
{% for lang in supported_languages %}
|
||||
<button
|
||||
type="button"
|
||||
role="menuitem"
|
||||
class="flex items-center w-full px-4 py-2 text-sm text-left hover:bg-gray-100 {% if current_locale == lang.code %}bg-blue-50 text-blue-700 font-medium{% else %}text-gray-700{% endif %}"
|
||||
onclick="setLanguage('{{ lang.code }}')"
|
||||
>
|
||||
<span class="mr-2">{{ lang.flag }}</span>
|
||||
<span>{{ lang.native }}</span>
|
||||
{% if current_locale == lang.code %}
|
||||
<i class="fas fa-check ml-auto text-blue-500" aria-hidden="true"></i>
|
||||
{% endif %}
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dark mode toggle -->
|
||||
<button
|
||||
id="darkModeToggle"
|
||||
onclick="toggleDarkMode()"
|
||||
type="button"
|
||||
class="p-1.5 rounded-md text-gray-500 hover:text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500"
|
||||
aria-label="Toggle dark mode"
|
||||
title="Toggle dark mode"
|
||||
aria-label="{{ _('nav.toggle_dark_mode') }}"
|
||||
title="{{ _('nav.toggle_dark_mode') }}"
|
||||
>
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
@@ -235,10 +286,10 @@
|
||||
type="button"
|
||||
class="md:hidden inline-flex items-center justify-center p-3 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
|
||||
style="min-height:44px;min-width:44px;"
|
||||
aria-label="Toggle navigation menu"
|
||||
aria-label="{{ _('nav.toggle_nav') }}"
|
||||
:aria-expanded="mobileMenuOpen"
|
||||
>
|
||||
<span class="sr-only">Open main menu</span>
|
||||
<span class="sr-only">{{ _("nav.open_main_menu") }}</span>
|
||||
<svg class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
@@ -262,12 +313,12 @@
|
||||
<a href="/pricing"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/pricing' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-tag mr-2 text-gray-400" aria-hidden="true"></i>Pricing
|
||||
<i class="fas fa-tag mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.pricing") }}
|
||||
</a>
|
||||
<a href="/about"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/about' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-info-circle mr-2 text-gray-400" aria-hidden="true"></i>About
|
||||
<i class="fas fa-info-circle mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.about") }}
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
@@ -275,87 +326,87 @@
|
||||
<a href="/"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-home mr-2 text-gray-400" aria-hidden="true"></i>Dashboard
|
||||
<i class="fas fa-home mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.dashboard") }}
|
||||
</a>
|
||||
<a href="/upload"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-blue-600 hover:text-blue-800 hover:bg-blue-50"
|
||||
{% if request and request.url.path == '/upload' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-upload mr-2" aria-hidden="true"></i>Upload
|
||||
<i class="fas fa-upload mr-2" aria-hidden="true"></i>{{ _("nav.upload") }}
|
||||
</a>
|
||||
<a href="/files"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/files' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-folder-open mr-2 text-gray-400" aria-hidden="true"></i>Files
|
||||
<i class="fas fa-folder-open mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.files") }}
|
||||
</a>
|
||||
<a href="/search"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/search' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-search mr-2 text-gray-400" aria-hidden="true"></i>Search
|
||||
<i class="fas fa-search mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.search") }}
|
||||
</a>
|
||||
<a href="/pipelines"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/pipelines' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-project-diagram mr-2 text-gray-400" aria-hidden="true"></i>Pipelines
|
||||
<i class="fas fa-project-diagram mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.pipelines") }}
|
||||
</a>
|
||||
<a href="/integrations"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/integrations' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-plug mr-2 text-gray-400" aria-hidden="true"></i>Integrations
|
||||
<i class="fas fa-plug mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.integrations") }}
|
||||
</a>
|
||||
<a href="/notifications"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/notifications' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-bell mr-2 text-gray-400" aria-hidden="true"></i>Notifications
|
||||
<i class="fas fa-bell mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.notifications") }}
|
||||
</a>
|
||||
|
||||
<!-- Admin section in mobile menu – shown only for admin users via JS -->
|
||||
<div id="mobileAdminSection" class="hidden">
|
||||
<div class="border-t border-gray-200 mt-1 pt-1">
|
||||
<p class="px-3 py-1 text-xs font-semibold text-red-600 uppercase tracking-wider flex items-center">
|
||||
<i class="fas fa-shield-alt mr-1" aria-hidden="true"></i> Admin
|
||||
<i class="fas fa-shield-alt mr-1" aria-hidden="true"></i> {{ _("nav.admin") }}
|
||||
</p>
|
||||
<a href="/settings" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-cog mr-2 text-gray-400" aria-hidden="true"></i> Settings
|
||||
<i class="fas fa-cog mr-2 text-gray-400" aria-hidden="true"></i> {{ _("nav.settings") }}
|
||||
</a>
|
||||
<a href="/admin/users" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-users mr-2 text-blue-400" aria-hidden="true"></i> Users
|
||||
<i class="fas fa-users mr-2 text-blue-400" aria-hidden="true"></i> {{ _("nav.users") }}
|
||||
</a>
|
||||
<a href="/admin/plans" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-layer-group mr-2 text-indigo-400" aria-hidden="true"></i> Plan Designer
|
||||
<i class="fas fa-layer-group mr-2 text-indigo-400" aria-hidden="true"></i> {{ _("nav.plan_designer") }}
|
||||
</a>
|
||||
<a href="/admin/credentials" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-key mr-2 text-yellow-400" aria-hidden="true"></i> Credentials
|
||||
<i class="fas fa-key mr-2 text-yellow-400" aria-hidden="true"></i> {{ _("nav.credentials") }}
|
||||
</a>
|
||||
<a href="/admin/files" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-folder-open mr-2 text-gray-400" aria-hidden="true"></i> File Manager
|
||||
<i class="fas fa-folder-open mr-2 text-gray-400" aria-hidden="true"></i> {{ _("nav.file_manager") }}
|
||||
</a>
|
||||
<a href="/duplicates" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-clone mr-2 text-orange-400" aria-hidden="true"></i> Duplicates
|
||||
<i class="fas fa-clone mr-2 text-orange-400" aria-hidden="true"></i> {{ _("nav.duplicates") }}
|
||||
</a>
|
||||
<a href="/similarity" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-sitemap mr-2 text-purple-400" aria-hidden="true"></i> Similarity
|
||||
<i class="fas fa-sitemap mr-2 text-purple-400" aria-hidden="true"></i> {{ _("nav.similarity") }}
|
||||
</a>
|
||||
<a href="/admin/queue" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-stream mr-2 text-blue-400" aria-hidden="true"></i> Queue Monitor
|
||||
<i class="fas fa-stream mr-2 text-blue-400" aria-hidden="true"></i> {{ _("nav.queue_monitor") }}
|
||||
</a>
|
||||
<a href="/admin/scheduled-jobs" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-clock mr-2 text-indigo-500" aria-hidden="true"></i> Scheduled Jobs
|
||||
<i class="fas fa-clock mr-2 text-indigo-500" aria-hidden="true"></i> {{ _("nav.scheduled_jobs") }}
|
||||
</a>
|
||||
<a href="/admin/compliance" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-check-double mr-2 text-green-500" aria-hidden="true"></i> Compliance
|
||||
</a>
|
||||
<a href="/admin/backup" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-database mr-2 text-green-500" aria-hidden="true"></i> Backup & Restore
|
||||
<i class="fas fa-database mr-2 text-green-500" aria-hidden="true"></i> {{ _("nav.backup_restore") }}
|
||||
</a>
|
||||
<a href="/status" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
{% if request and request.url.path == '/status' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-dot mr-2 text-gray-400" aria-hidden="true"></i> Status
|
||||
<i class="fas fa-circle-dot mr-2 text-gray-400" aria-hidden="true"></i> {{ _("nav.status") }}
|
||||
</a>
|
||||
<a href="/admin/api-docs" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-code mr-2 text-teal-400" aria-hidden="true"></i> API Docs
|
||||
<i class="fas fa-code mr-2 text-teal-400" aria-hidden="true"></i> {{ _("nav.api_docs") }}
|
||||
</a>
|
||||
<a href="/developer-docs/" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-book mr-2 text-teal-400" aria-hidden="true"></i> Developer Docs
|
||||
<i class="fas fa-book mr-2 text-teal-400" aria-hidden="true"></i> {{ _("nav.developer_docs") }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -365,9 +416,9 @@
|
||||
<!-- Help – always visible, for every visitor regardless of auth state -->
|
||||
<a href="/help"
|
||||
class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
aria-label="Help Center"
|
||||
aria-label="{{ _('nav.help_center') }}"
|
||||
{% if request and request.url.path == '/help' %}aria-current="page"{% endif %}>
|
||||
<i class="fas fa-circle-question mr-2 text-gray-400" aria-hidden="true"></i>Help
|
||||
<i class="fas fa-circle-question mr-2 text-gray-400" aria-hidden="true"></i>{{ _("nav.help") }}
|
||||
</a>
|
||||
|
||||
<!-- Dark mode toggle (mobile) -->
|
||||
@@ -376,10 +427,10 @@
|
||||
type="button"
|
||||
class="flex items-center w-full px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50"
|
||||
id="darkModeToggleMobile"
|
||||
aria-label="Toggle dark mode"
|
||||
aria-label="{{ _('nav.toggle_dark_mode') }}"
|
||||
>
|
||||
<i class="fas fa-moon mr-2" id="darkModeIconMobile" aria-hidden="true"></i>
|
||||
<span id="darkModeTextMobile">Dark Mode</span>
|
||||
<span id="darkModeTextMobile">{{ _("nav.dark_mode") }}</span>
|
||||
</button>
|
||||
|
||||
<!-- Mobile Auth / Account section (populated by common.js) -->
|
||||
@@ -400,14 +451,14 @@
|
||||
<!-- Footer -->
|
||||
<footer class="bg-white shadow" role="contentinfo">
|
||||
<div class="max-w-7xl mx-auto px-4 py-4 text-center text-gray-600">
|
||||
DocuElevate 2025 -
|
||||
<nav aria-label="Footer navigation" class="inline">
|
||||
<a href="/privacy" class="text-blue-500 hover:underline">Privacy</a> -
|
||||
<a href="/imprint" class="text-blue-500 hover:underline">Imprint</a> -
|
||||
<a href="/terms" class="text-blue-500 hover:underline">Terms</a> -
|
||||
<a href="/cookies" class="text-blue-500 hover:underline">Cookies</a> -
|
||||
<a href="/license" class="text-blue-500 hover:underline">License</a> -
|
||||
<a href="/attribution" class="text-blue-500 hover:underline">Attributions</a>
|
||||
{{ _("footer.copyright", year="2025") }} -
|
||||
<nav aria-label="{{ _('footer.navigation') }}" class="inline">
|
||||
<a href="/privacy" class="text-blue-500 hover:underline">{{ _("footer.privacy") }}</a> -
|
||||
<a href="/imprint" class="text-blue-500 hover:underline">{{ _("footer.imprint") }}</a> -
|
||||
<a href="/terms" class="text-blue-500 hover:underline">{{ _("footer.terms") }}</a> -
|
||||
<a href="/cookies" class="text-blue-500 hover:underline">{{ _("footer.cookies") }}</a> -
|
||||
<a href="/license" class="text-blue-500 hover:underline">{{ _("footer.license") }}</a> -
|
||||
<a href="/attribution" class="text-blue-500 hover:underline">{{ _("footer.attributions") }}</a>
|
||||
</nav> -
|
||||
<span class="text-xs">Version {{ app_version|default(version, true) }}{% if release_name %} "{{ release_name }}"{% endif %}</span>
|
||||
</div>
|
||||
@@ -422,19 +473,18 @@
|
||||
style="display:none!important"
|
||||
aria-live="polite"
|
||||
role="region"
|
||||
aria-label="Cookie notice">
|
||||
aria-label="{{ _('cookie.notice_label') }}">
|
||||
<p class="text-center sm:text-left">
|
||||
DocuElevate uses only essential session cookies required for authentication and service operation.
|
||||
No tracking or analytics cookies are used.
|
||||
<a href="/cookies" class="underline hover:text-blue-300 ml-1">Cookie Policy</a> ·
|
||||
<a href="/privacy" class="underline hover:text-blue-300 ml-1">Privacy Notice</a>
|
||||
{{ _("cookie.notice") }}
|
||||
<a href="/cookies" class="underline hover:text-blue-300 ml-1">{{ _("cookie.policy_link") }}</a> ·
|
||||
<a href="/privacy" class="underline hover:text-blue-300 ml-1">{{ _("cookie.privacy_link") }}</a>
|
||||
</p>
|
||||
<button
|
||||
id="cookieNoticeAccept"
|
||||
type="button"
|
||||
class="flex-shrink-0 bg-blue-600 hover:bg-blue-700 text-white font-semibold px-4 py-1.5 rounded focus:outline-none focus:ring-2 focus:ring-blue-400"
|
||||
aria-label="Acknowledge cookie notice">
|
||||
Got it
|
||||
aria-label="{{ _('cookie.accept') }}">
|
||||
{{ _("cookie.accept") }}
|
||||
</button>
|
||||
</div>
|
||||
<script>
|
||||
@@ -457,6 +507,26 @@
|
||||
<!-- Common JS (shared) -->
|
||||
<script src="/static/js/common.js"></script>
|
||||
|
||||
<!-- Language selector -->
|
||||
<script>
|
||||
function setLanguage(langCode) {
|
||||
var csrfToken = document.querySelector('meta[name="csrf-token"]');
|
||||
var headers = { 'Content-Type': 'application/json' };
|
||||
if (csrfToken && csrfToken.content) {
|
||||
headers['X-CSRF-Token'] = csrfToken.content;
|
||||
}
|
||||
fetch('/api/i18n/language', {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: JSON.stringify({ language: langCode })
|
||||
}).then(function() {
|
||||
window.location.reload();
|
||||
}).catch(function() {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Notification badge updater -->
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Езикът беше променен на {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Български",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "L'idioma s'ha canviat a {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Català",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Jazyk byl změněn na {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Čeština",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Sproget blev ændret til {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Dansk",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,511 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Passwort bestätigen",
|
||||
"auth.display_name_label": "Anzeigename",
|
||||
"auth.email_label": "E-Mail",
|
||||
"auth.forgot_password": "Passwort vergessen?",
|
||||
"auth.login": "Anmelden",
|
||||
"auth.login_title": "Anmelden",
|
||||
"auth.logout": "Abmelden",
|
||||
"auth.my_account": "Mein Konto",
|
||||
"auth.password_label": "Passwort",
|
||||
"auth.profile": "Profil",
|
||||
"auth.remember_me": "Angemeldet bleiben",
|
||||
"auth.signup": "Registrieren",
|
||||
"auth.signup_title": "Registrieren",
|
||||
"auth.username_label": "Benutzername",
|
||||
"common.actions": "Aktionen",
|
||||
"common.active": "Aktiv",
|
||||
"common.all": "Alle",
|
||||
"common.back": "Zurück",
|
||||
"common.cancel": "Abbrechen",
|
||||
"common.close": "Schließen",
|
||||
"common.completed": "Abgeschlossen",
|
||||
"common.confirm": "Bestätigen",
|
||||
"common.copied": "Kopiert!",
|
||||
"common.copy": "Kopieren",
|
||||
"common.create": "Erstellen",
|
||||
"common.created": "Erstellt",
|
||||
"common.date": "Datum",
|
||||
"common.delete": "Löschen",
|
||||
"common.description": "Beschreibung",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Deaktiviert",
|
||||
"common.download": "Herunterladen",
|
||||
"common.duplicate": "Duplikat",
|
||||
"common.edit": "Bearbeiten",
|
||||
"common.enabled": "Aktiviert",
|
||||
"common.error": "Fehler",
|
||||
"common.failed": "Fehlgeschlagen",
|
||||
"common.filter": "Filtern",
|
||||
"common.inactive": "Inaktiv",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Laden...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Weiter",
|
||||
"common.no": "Nein",
|
||||
"common.none": "Keine",
|
||||
"common.pending": "Ausstehend",
|
||||
"common.previous": "Zurück",
|
||||
"common.processing": "Verarbeitung",
|
||||
"common.refresh": "Aktualisieren",
|
||||
"common.reset": "Zurücksetzen",
|
||||
"common.retry": "Erneut versuchen",
|
||||
"common.save": "Speichern",
|
||||
"common.search": "Suche",
|
||||
"common.select": "Auswählen",
|
||||
"common.size": "Größe",
|
||||
"common.status": "Status",
|
||||
"common.submit": "Absenden",
|
||||
"common.success": "Erfolg",
|
||||
"common.tags": "Tags",
|
||||
"common.type": "Typ",
|
||||
"common.updated": "Aktualisiert",
|
||||
"common.upload": "Hochladen",
|
||||
"common.view": "Ansehen",
|
||||
"common.warning": "Warnung",
|
||||
"common.yes": "Ja",
|
||||
"cookie.accept": "Akzeptieren",
|
||||
"cookie.learn_more": "Mehr erfahren",
|
||||
"cookie.message": "Diese Website verwendet Cookies, um Ihr Erlebnis zu verbessern.",
|
||||
"cookie.notice": "DocuElevate verwendet nur essentielle Sitzungscookies, die für die Authentifizierung und den Servicebetrieb erforderlich sind. Es werden keine Tracking- oder Analyse-Cookies verwendet.",
|
||||
"cookie.notice_label": "Cookie-Hinweis",
|
||||
"cookie.policy_link": "Cookie-Richtlinie",
|
||||
"cookie.privacy_link": "Datenschutzhinweis",
|
||||
"dashboard.active_integrations": "Aktive Integrationen",
|
||||
"dashboard.files_this_month": "Dateien diesen Monat",
|
||||
"dashboard.files_today": "Dateien heute",
|
||||
"dashboard.ocr_processed": "OCR verarbeitet",
|
||||
"dashboard.quick_actions": "Schnellaktionen",
|
||||
"dashboard.recent_activity": "Letzte Aktivitäten",
|
||||
"dashboard.storage_targets": "Speicherziele",
|
||||
"dashboard.title": "Übersicht",
|
||||
"dashboard.total_files": "Dateien gesamt",
|
||||
"dashboard.welcome": "Willkommen bei DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Ups, diese Seite konnten wir nicht finden!",
|
||||
"error.404_home": "Zur Startseite",
|
||||
"error.404_message": "Es scheint, als hätte DocuElevate das gesuchte Dokument verlegt. Keine Sorge – wir helfen Ihnen weiter.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Unsere Server haben ein Problem und brauchen einen Moment.",
|
||||
"error.500_heading": "Ups! Etwas ist schiefgelaufen.",
|
||||
"error.500_home": "Zur Startseite",
|
||||
"error.forbidden": "Zugriff verweigert",
|
||||
"error.forbidden_message": "Sie haben keine Berechtigung, auf diese Seite zuzugreifen.",
|
||||
"error.not_found": "Seite nicht gefunden",
|
||||
"error.not_found_message": "Die gesuchte Seite existiert nicht.",
|
||||
"error.server_error": "Interner Serverfehler",
|
||||
"error.server_error_message": "Etwas ist schiefgelaufen. Bitte versuchen Sie es später erneut.",
|
||||
"error.unauthorized": "Nicht autorisiert",
|
||||
"error.unauthorized_message": "Sie müssen sich anmelden, um auf diese Seite zuzugreifen.",
|
||||
"files.action_delete": "Datei löschen",
|
||||
"files.action_details": "Details anzeigen",
|
||||
"files.action_preview": "Schnellvorschau",
|
||||
"files.bulk_clear_selection": "Auswahl aufheben",
|
||||
"files.bulk_cloud_ocr": "Cloud-OCR erneut ausführen",
|
||||
"files.bulk_delete": "Ausgewählte löschen",
|
||||
"files.bulk_download": "Als ZIP herunterladen",
|
||||
"files.bulk_reprocess": "Ausgewählte erneut verarbeiten",
|
||||
"files.delete_modal_cancel": "Abbrechen",
|
||||
"files.delete_modal_confirm": "Löschen",
|
||||
"files.delete_modal_message": "Sind Sie sicher, dass Sie diese Datei löschen möchten?",
|
||||
"files.delete_modal_title": "Löschung bestätigen",
|
||||
"files.document_title": "Dokumenttitel",
|
||||
"files.drop_overlay_hint": "Unterstützt PDF, Office-Dokumente, Bilder, HTML, Markdown und mehr",
|
||||
"files.drop_overlay_title": "Dateien oder Ordner zum Hochladen hier ablegen",
|
||||
"files.file_size": "Dateigröße",
|
||||
"files.filename": "Dateiname",
|
||||
"files.filter_all_providers": "Alle Anbieter",
|
||||
"files.filter_all_statuses": "Alle Status",
|
||||
"files.filter_all_types": "Alle Typen",
|
||||
"files.filter_apply": "Filter anwenden",
|
||||
"files.filter_clear": "Zurücksetzen",
|
||||
"files.filter_date_from": "Datum von",
|
||||
"files.filter_date_to": "Datum bis",
|
||||
"files.filter_mime_type": "MIME-Typ",
|
||||
"files.filter_ocr_all": "Alle Dateien",
|
||||
"files.filter_ocr_good": "Gute Qualität",
|
||||
"files.filter_ocr_poor": "Schlechte Qualität",
|
||||
"files.filter_ocr_quality": "OCR-Qualität",
|
||||
"files.filter_ocr_unchecked": "Noch nicht bewertet",
|
||||
"files.filter_search_placeholder": "Dateinamen eingeben...",
|
||||
"files.filter_storage_provider": "Speicheranbieter",
|
||||
"files.filter_tags_placeholder": "z.B. Rechnung,Amazon",
|
||||
"files.fulltext_search_label": "Volltextsuche",
|
||||
"files.fulltext_search_placeholder": "Dokumentinhalt, Absender, Tags, Typ durchsuchen...",
|
||||
"files.no_files": "Keine Dateien gefunden",
|
||||
"files.ocr_status": "OCR-Status",
|
||||
"files.page_title": "Dateiübersicht",
|
||||
"files.pagination_first": "Erste",
|
||||
"files.pagination_last": "Letzte",
|
||||
"files.pagination_next": "Nächste",
|
||||
"files.pagination_previous": "Vorherige",
|
||||
"files.preview_modal_close": "Vorschau schließen",
|
||||
"files.preview_modal_title": "Vorschau",
|
||||
"files.queue_banner_link": "Warteschlange ansehen",
|
||||
"files.saved_searches_empty": "Noch keine gespeicherten Suchen",
|
||||
"files.saved_searches_error": "Gespeicherte Suchen konnten nicht geladen werden",
|
||||
"files.saved_searches_label": "Gespeicherte Suchen",
|
||||
"files.saved_searches_save": "Aktuelle speichern",
|
||||
"files.search_results_empty": "Keine Ergebnisse gefunden.",
|
||||
"files.search_results_title": "Suchergebnisse",
|
||||
"files.table_actions": "Aktionen",
|
||||
"files.table_created_at": "Erstellt am",
|
||||
"files.table_empty": "Keine Dateien gefunden",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME-Typ",
|
||||
"files.table_original_filename": "Originaler Dateiname",
|
||||
"files.table_select_all": "Alle Dateien auf dieser Seite auswählen",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Dateien",
|
||||
"files.upload_modal_header": "Dateien hochladen",
|
||||
"files.uploaded": "Hochgeladen",
|
||||
"footer.about": "Über uns",
|
||||
"footer.attribution": "Namensnennung",
|
||||
"footer.attributions": "Quellenangaben",
|
||||
"footer.cookies": "Cookie-Richtlinie",
|
||||
"footer.copyright": "© {year} DocuElevate",
|
||||
"footer.imprint": "Impressum",
|
||||
"footer.license": "Lizenz",
|
||||
"footer.navigation": "Fußzeilennavigation",
|
||||
"footer.privacy": "Datenschutz",
|
||||
"footer.terms": "Nutzungsbedingungen",
|
||||
"footer.version": "Version",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-verknüpft. Dateien landen in Ihrem gewählten Ordner.",
|
||||
"help.destinations_email": "E-Mail-Weiterleitung",
|
||||
"help.destinations_email_desc": "Verarbeitete Dateien als SMTP-Anhänge gesendet.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Dienstkonto oder OAuth. Unterstützt geteilte Laufwerke.",
|
||||
"help.destinations_heading": "Ziele – Wohin die Dokumente gehen",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Selbstgehosteter Cloud-Speicher über WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API-Integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Dokumente direkt in Paperless zur Archivierung übertragen.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Jeder S3-kompatible Bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Sichere Dateiübertragung auf beliebige Server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "Metadaten per POST an einen externen Endpunkt senden.",
|
||||
"help.documentation": "Dokumentation",
|
||||
"help.faq": "Häufig gestellte Fragen",
|
||||
"help.faq_1_a": "Navigieren Sie zur Upload-Seite, ziehen Sie Ihre Dateien per Drag-and-Drop oder klicken Sie auf Datei auswählen. DocuElevate konvertiert Bilder und Office-Dokumente in PDF, führt OCR durch und extrahiert Metadaten automatisch.",
|
||||
"help.faq_1_q": "Wie lade ich Dokumente hoch?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF und HTML. Nicht-PDF-Dateien werden vor der Verarbeitung automatisch in PDF konvertiert.",
|
||||
"help.faq_2_q": "Welche Dateiformate werden unterstützt?",
|
||||
"help.faq_3_a": "Ja. Gehen Sie zu E-Mail-Import, fügen Sie ein IMAP-Konto hinzu, und DocuElevate prüft auf neue Nachrichten und verarbeitet Anhänge automatisch.",
|
||||
"help.faq_3_q": "Kann ich Dokumente per E-Mail importieren?",
|
||||
"help.faq_4_a": "Pipelines ermöglichen es Ihnen, Verarbeitungsschritte zu verketten – OCR, KI-Extraktion, Formatkonvertierung – und das Ergebnis an ein oder mehrere Ziele weiterzuleiten. Erstellen und verwalten Sie diese auf der Pipelines-Seite.",
|
||||
"help.faq_4_q": "Wie funktionieren Verarbeitungs-Pipelines?",
|
||||
"help.faq_5_a": "DocuElevate verschlüsselt Anmeldedaten im Ruhezustand, kommuniziert über TLS und speichert Ihre Dokumente nie länger als nötig. Weitere Details finden Sie in der Datenschutzerklärung.",
|
||||
"help.faq_5_q": "Sind meine Daten sicher?",
|
||||
"help.faq_heading": "Häufig gestellte Fragen",
|
||||
"help.getting_started": "Erste Schritte",
|
||||
"help.heading": "Hilfezentrum",
|
||||
"help.page_title": "Hilfezentrum",
|
||||
"help.quickstart_heading": "Schnellstart",
|
||||
"help.quickstart_storage": "Speicher verbinden",
|
||||
"help.quickstart_storage_desc": "Gehen Sie zu Einstellungen und verknüpfen Sie Ihre Cloud-Konten. Verarbeitete Dokumente werden automatisch an jedes konfigurierte Ziel weitergeleitet.",
|
||||
"help.quickstart_upload": "Dokumente hochladen",
|
||||
"help.quickstart_upload_desc": "Ziehen Sie Dateien auf die Upload-Seite oder klicken Sie auf Datei auswählen. DocuElevate konvertiert Bilder und Office-Dokumente in PDF, führt OCR durch und extrahiert Metadaten automatisch.",
|
||||
"help.quickstart_workflows": "Arbeitsabläufe automatisieren",
|
||||
"help.quickstart_workflows_desc": "Erstellen Sie Pipelines, um mehrstufige Verarbeitungs- und Weiterleitungsregeln zu definieren. Kombinieren Sie OCR, KI-Extraktion, Formatkonvertierung und Zustellung in einem einzigen Ablauf.",
|
||||
"help.sources_email_ingestion": "E-Mail-Import (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Leiten Sie Dokumente an ein dediziertes Postfach weiter. Unter E-Mail-Import fügen Sie ein oder mehrere IMAP-Konten hinzu. DocuElevate prüft auf neue Nachrichten und verarbeitet Anhänge automatisch.",
|
||||
"help.sources_heading": "Quellen – Dokumente einbringen",
|
||||
"help.sources_rest_api": "REST-API",
|
||||
"help.sources_rest_api_desc": "Integrieren Sie programmgesteuert, indem Sie Dateien an /api/upload senden. Ideal für Skripte, überwachte Ordner, Scanner oder Drittanbieter-Tools wie Zapier und n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobil",
|
||||
"help.sources_scanner_desc": "Richten Sie Netzwerkscanner auf den Upload-Endpunkt von DocuElevate oder verwenden Sie eine mobile Scan-App, die benutzerdefinierte HTTP-Ziele unterstützt.",
|
||||
"help.sources_web_upload": "Web-Upload",
|
||||
"help.sources_web_upload_desc": "Der schnellste Weg, um loszulegen. Öffnen Sie die Upload-Seite, legen Sie eine oder mehrere Dateien ab, und DocuElevate kümmert sich um den Rest. Unterstützte Formate sind PDF, JPEG, PNG, TIFF, DOCX, XLSX und mehr.",
|
||||
"help.subheading": "Alles, was Sie brauchen, um DocuElevate optimal zu nutzen. Durchsuchen Sie die Themen unten oder suchen Sie nach dem, was Sie brauchen.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Wenden Sie sich an Ihren Administrator für Support-Informationen.",
|
||||
"help.support_description": "Können Sie nicht finden, was Sie suchen? Unser Support-Team hilft Ihnen gerne weiter.",
|
||||
"help.support_heading": "Support kontaktieren",
|
||||
"help.title": "Hilfecenter",
|
||||
"help.workflows_creating": "Eine Pipeline erstellen",
|
||||
"help.workflows_definition": "Eine Pipeline ist eine Reihe von Verarbeitungsschritten, die automatisch ausgeführt werden, wenn ein Dokument aufgenommen wird. Jeder Schritt kann das Dokument transformieren, anreichern oder weiterleiten.",
|
||||
"help.workflows_heading": "Arbeitsabläufe & Pipelines",
|
||||
"help.workflows_step_1": "In PDF konvertieren",
|
||||
"help.workflows_step_1_create": "Gehen Sie im Hauptmenü zu Pipelines.",
|
||||
"help.workflows_step_2": "OCR – Text extrahieren",
|
||||
"help.workflows_step_2_create": "Klicken Sie auf Neue Pipeline und geben Sie ihr einen Namen.",
|
||||
"help.workflows_step_3": "KI-Metadatenextraktion",
|
||||
"help.workflows_step_3_create": "Fügen Sie die benötigten Verarbeitungsschritte hinzu.",
|
||||
"help.workflows_step_4": "An ein oder mehrere Ziele liefern",
|
||||
"help.workflows_step_4_create": "Wählen Sie ein oder mehrere Zustellungsziele.",
|
||||
"help.workflows_step_5_create": "Speichern – neue Dokumente werden automatisch durch diese Pipeline verarbeitet.",
|
||||
"help.workflows_typical_steps": "Typische Schritte",
|
||||
"help.workflows_what_is": "Was ist eine Pipeline?",
|
||||
"index.badge_intelligent": "Intelligente Dokumentenverarbeitung",
|
||||
"index.capabilities_cloud": "Cloud-Speicher: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "E-Mail- & URL-basierte Dokumentenaufnahme",
|
||||
"index.capabilities_ocr": "OCR & Metadatenextraktion mit KI",
|
||||
"index.capabilities_paperless": "Paperless-ngx-Integration für Dokumentenverwaltung",
|
||||
"index.capabilities_title": "Funktionen",
|
||||
"index.capabilities_workflows": "Automatisierte Klassifizierung & Routing-Workflows",
|
||||
"index.cta_description": "Schließen Sie sich Teams an, die ihre Dokumentenverarbeitung bereits mit DocuElevate automatisieren.",
|
||||
"index.cta_heading": "Bereit, Ihren Dokumenten-Workflow zu verbessern?",
|
||||
"index.cta_pricing": "Preise ansehen",
|
||||
"index.cta_signup": "Kostenloses Konto erstellen",
|
||||
"index.dashboard_subtitle": "Intelligente Dokumentenverarbeitung & -verwaltung",
|
||||
"index.feature_ai": "KI-Metadatenextraktion",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini und andere KI-Anbieter klassifizieren Dokumente und extrahieren wichtige Felder wie Daten, Beträge und Betreffzeilen.",
|
||||
"index.feature_cloud": "Multi-Cloud-Speicher",
|
||||
"index.feature_cloud_desc": "Leiten Sie verarbeitete Dateien an Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP und mehr weiter.",
|
||||
"index.feature_email": "E-Mail- & IMAP-Import",
|
||||
"index.feature_email_desc": "Ziehen Sie Dokumente automatisch aus Gmail oder jedem IMAP-Postfach – keine manuellen Uploads nötig.",
|
||||
"index.feature_ocr": "OCR & Texterkennung",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence konvertiert gescannte PDFs und Bilder automatisch in vollständig durchsuchbaren Text.",
|
||||
"index.feature_pipelines": "Benutzerdefinierte Pipelines",
|
||||
"index.feature_pipelines_desc": "Erstellen Sie Verarbeitungs-Pipelines mit konfigurierbaren Schritten – OCR, KI-Extraktion, Formatkonvertierung und Speicher-Routing in beliebiger Reihenfolge.",
|
||||
"index.feature_search": "Volltextsuche",
|
||||
"index.feature_search_desc": "Finden Sie sofort jedes Dokument nach Inhalt, Metadaten oder Tags in Ihrem gesamten Archiv.",
|
||||
"index.feature_section_title": "Alles, was Sie für intelligente Dokumenten-Workflows brauchen",
|
||||
"index.getting_started": "Erste Schritte",
|
||||
"index.getting_started_1": "Integrationen über Systemstatus konfigurieren",
|
||||
"index.getting_started_2": "Erstes Dokument hochladen",
|
||||
"index.getting_started_3": "Ergebnisse in Dateien überprüfen",
|
||||
"index.getting_started_learn": "Mehr über DocuElevate erfahren",
|
||||
"index.hero_description": "DocuElevate nimmt Ihre Dokumente auf, führt OCR durch, extrahiert Metadaten mit KI und leitet Dateien an Dropbox, Google Drive, OneDrive, S3, Nextcloud und mehr weiter – alles in einer nahtlosen Pipeline.",
|
||||
"index.hero_heading": "Vom Hochladen zur Erkenntnis – automatisch.",
|
||||
"index.hero_login": "Anmelden",
|
||||
"index.hero_pricing": "Tarife & Preise ansehen",
|
||||
"index.hero_signup": "Kostenlos starten",
|
||||
"index.integrations_active": "Aktive Integrationen",
|
||||
"index.integrations_storage": "Speicherziele",
|
||||
"index.integrations_title": "Integrationen",
|
||||
"index.integrations_view_status": "Systemstatus anzeigen",
|
||||
"index.page_title_dashboard": "Übersicht",
|
||||
"index.page_title_public": "Intelligente Dokumentenverarbeitung",
|
||||
"index.platform_overview": "Plattformübersicht",
|
||||
"index.quick_actions": "Schnellaktionen",
|
||||
"index.quick_documents": "Meine Dokumente",
|
||||
"index.quick_documents_desc": "Ihre verarbeiteten Dateien durchsuchen",
|
||||
"index.quick_search": "Suche",
|
||||
"index.quick_search_desc": "Volltextsuche über Dokumente",
|
||||
"index.quick_subscription": "Mein Abonnement",
|
||||
"index.quick_subscription_desc": "Tarif & Nutzungsdetails anzeigen",
|
||||
"index.quick_upload": "Dokument hochladen",
|
||||
"index.quick_upload_desc": "Eine neue Datei verarbeiten",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligente Dokumentenverarbeitung & -verwaltung",
|
||||
"index.stat_active_users": "Aktive Benutzer",
|
||||
"index.stat_files_month": "Dateien diesen Monat",
|
||||
"index.stat_files_today": "Dateien heute",
|
||||
"index.stat_total_files": "Dateien gesamt",
|
||||
"index.tier_plan": "Tarif",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "Alle Details ansehen",
|
||||
"index.upgrade_daily_limits": "Höhere tägliche & monatliche Limits",
|
||||
"index.upgrade_description": "Mehr Dokumente, mehr Ziele und Prioritäts-Support freischalten.",
|
||||
"index.upgrade_destinations": "Mehr Speicherziele",
|
||||
"index.upgrade_ocr_pages": "Mehr OCR-Seiten",
|
||||
"index.upgrade_plan": "Tarif upgraden",
|
||||
"index.upgrade_view_pricing": "Tarife & Preise ansehen",
|
||||
"index.usage_lifetime": "Dateien gesamt",
|
||||
"index.usage_month": "Dateien diesen Monat",
|
||||
"index.usage_my_usage": "Meine Nutzung",
|
||||
"index.usage_today": "Dateien heute",
|
||||
"index.usage_unlimited": "Unbegrenzt",
|
||||
"integrations.configure": "Konfigurieren",
|
||||
"integrations.connect": "Verbinden",
|
||||
"integrations.connected": "Verbunden",
|
||||
"integrations.disconnect": "Trennen",
|
||||
"integrations.empty_state": "Keine Integrationen konfiguriert",
|
||||
"integrations.folder_label": "Ordner",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP-Einstellungen",
|
||||
"integrations.not_connected": "Nicht verbunden",
|
||||
"integrations.page_title": "Integrationen",
|
||||
"integrations.password_label": "Passwort",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrationen",
|
||||
"integrations.username_label": "Benutzername",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.change_success": "Sprache geändert zu {language}",
|
||||
"language.changed": "Sprache geändert zu {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "Englisch",
|
||||
"language.es": "Spanisch",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Französisch",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italienisch",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Niederländisch",
|
||||
"language.pl": "Polnisch",
|
||||
"language.pt": "Portugiesisch",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Russisch",
|
||||
"language.selector": "Sprache",
|
||||
"language.selector_label": "Sprache wählen",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "Chinesisch",
|
||||
"nav.about": "Über uns",
|
||||
"nav.admin": "Administration",
|
||||
"nav.admin.audit_logs": "Prüfprotokolle",
|
||||
"nav.admin.backups": "Sicherungen",
|
||||
"nav.admin.plans": "Tarife",
|
||||
"nav.admin.scheduled_jobs": "Geplante Aufgaben",
|
||||
"nav.admin.users": "Benutzer",
|
||||
"nav.admin_actions": "Admin-Aktionen",
|
||||
"nav.admin_menu": "Admin-Menü",
|
||||
"nav.api_docs": "API-Dokumentation",
|
||||
"nav.api_tokens": "API-Token",
|
||||
"nav.backup_restore": "Sicherung & Wiederherstellung",
|
||||
"nav.credentials": "Zugangsdaten",
|
||||
"nav.dark_mode": "Dunkelmodus",
|
||||
"nav.dashboard": "Übersicht",
|
||||
"nav.developer_docs": "Entwicklerdokumentation",
|
||||
"nav.duplicates": "Duplikate",
|
||||
"nav.file_manager": "Dateimanager",
|
||||
"nav.files": "Dateien",
|
||||
"nav.help": "Hilfe",
|
||||
"nav.help_center": "Hilfecenter",
|
||||
"nav.imap": "E-Mail-Import",
|
||||
"nav.integrations": "Integrationen",
|
||||
"nav.light_mode": "Hellmodus",
|
||||
"nav.login": "Anmelden",
|
||||
"nav.logout": "Abmelden",
|
||||
"nav.main_navigation": "Hauptnavigation",
|
||||
"nav.notifications": "Benachrichtigungen",
|
||||
"nav.open_main_menu": "Hauptmenü öffnen",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan-Designer",
|
||||
"nav.pricing": "Preise",
|
||||
"nav.profile": "Profil",
|
||||
"nav.queue": "Warteschlange",
|
||||
"nav.queue_monitor": "Warteschlangen-Monitor",
|
||||
"nav.scheduled_jobs": "Geplante Aufgaben",
|
||||
"nav.search": "Suche",
|
||||
"nav.settings": "Einstellungen",
|
||||
"nav.shared_links": "Geteilte Links",
|
||||
"nav.signup": "Registrieren",
|
||||
"nav.similarity": "Ähnlichkeit",
|
||||
"nav.skip_to_content": "Zum Hauptinhalt springen",
|
||||
"nav.status": "Systemstatus",
|
||||
"nav.subscription": "Abonnement",
|
||||
"nav.toggle_dark_mode": "Dunkelmodus umschalten",
|
||||
"nav.toggle_nav": "Navigationsmenü umschalten",
|
||||
"nav.upload": "Hochladen",
|
||||
"nav.users": "Benutzer",
|
||||
"nav.version": "Versionsinformationen",
|
||||
"notifications.filter_all": "Alle",
|
||||
"notifications.filter_read": "Nur gelesene",
|
||||
"notifications.filter_unread": "Nur ungelesene",
|
||||
"notifications.manage_desc": "Verwalten Sie Ihren Posteingang, Ziele und Ereignispräferenzen",
|
||||
"notifications.mark_all_read": "Alle als gelesen markieren",
|
||||
"notifications.mark_all_read_btn": "Alle als gelesen markieren",
|
||||
"notifications.mark_read": "Als gelesen markieren",
|
||||
"notifications.no_notifications": "Keine Benachrichtigungen",
|
||||
"notifications.page_title": "Benachrichtigungen",
|
||||
"notifications.tab_inbox": "Posteingang",
|
||||
"notifications.tab_settings": "Einstellungen",
|
||||
"notifications.title": "Benachrichtigungen",
|
||||
"notifications.unread_count": "{count} ungelesene Benachrichtigungen",
|
||||
"pipelines.active_label": "Aktiv",
|
||||
"pipelines.create": "Pipeline erstellen",
|
||||
"pipelines.default_label": "Standard",
|
||||
"pipelines.description_label": "Beschreibung",
|
||||
"pipelines.disabled_label": "Deaktiviert",
|
||||
"pipelines.edit": "Pipeline bearbeiten",
|
||||
"pipelines.empty_state": "Noch keine Pipelines",
|
||||
"pipelines.enabled_label": "Aktiviert",
|
||||
"pipelines.inactive_label": "Inaktiv",
|
||||
"pipelines.page_title": "Verarbeitungs-Pipelines",
|
||||
"pipelines.set_default": "Als meine Standard-Pipeline festlegen",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Verarbeitungs-Pipelines",
|
||||
"search.button": "Suchen",
|
||||
"search.error_message": "Suche ist vorübergehend nicht verfügbar. Bitte versuchen Sie es gleich erneut.",
|
||||
"search.filter_clear_button": "Filter zurücksetzen",
|
||||
"search.filter_date_from": "Datum von",
|
||||
"search.filter_date_to": "Datum bis",
|
||||
"search.filter_document_type": "Dokumenttyp",
|
||||
"search.filter_document_type_placeholder": "z.B. Rechnung",
|
||||
"search.filter_language": "Sprache",
|
||||
"search.filter_language_placeholder": "z.B. de",
|
||||
"search.filter_sender": "Absender",
|
||||
"search.filter_sender_placeholder": "z.B. ACME GmbH",
|
||||
"search.filter_tags_placeholder": "z.B. Amazon",
|
||||
"search.filter_text_quality": "Textqualität",
|
||||
"search.filter_text_quality_all": "Alle",
|
||||
"search.filter_text_quality_high": "Hoch",
|
||||
"search.filter_text_quality_low": "Niedrig",
|
||||
"search.filter_text_quality_medium": "Mittel",
|
||||
"search.filter_text_quality_no_text": "Kein Text",
|
||||
"search.heading": "Dokumentensuche",
|
||||
"search.input_placeholder": "Dokumente nach Inhalt, Absender, Tags, Typ suchen...",
|
||||
"search.loading_indicator": "Suche läuft…",
|
||||
"search.no_results": "Keine Ergebnisse gefunden",
|
||||
"search.page_title": "Dokumente suchen",
|
||||
"search.placeholder": "Nach Dateiname, Inhalt, Tags suchen...",
|
||||
"search.result_empty": "Keine Dokumente gefunden, die Ihrer Suche entsprechen.",
|
||||
"search.results_count": "{count} Ergebnisse gefunden",
|
||||
"search.saved_button": "Aktuelle speichern",
|
||||
"search.saved_empty": "Noch keine gespeicherten Suchen",
|
||||
"search.saved_error": "Gespeicherte Suchen konnten nicht geladen werden",
|
||||
"search.saved_label": "Gespeicherte Suchen",
|
||||
"search.saved_loading": "Laden...",
|
||||
"search.title": "Dokumente suchen",
|
||||
"settings.reset_confirm": "Möchten Sie diese Einstellung wirklich zurücksetzen?",
|
||||
"settings.save_error": "Einstellung konnte nicht gespeichert werden",
|
||||
"settings.save_success": "Einstellung erfolgreich gespeichert",
|
||||
"settings.title": "Einstellungen",
|
||||
"status.app_version": "App-Version",
|
||||
"status.build_date": "Build-Datum",
|
||||
"status.container_id": "Container-ID",
|
||||
"status.git_commit": "Git-Commit",
|
||||
"status.last_check": "Letzte Prüfung",
|
||||
"status.page_title": "Systemstatus",
|
||||
"status.setting_label": "Einstellung",
|
||||
"status.value_label": "Wert",
|
||||
"upload.browse_button": "Dateien durchsuchen",
|
||||
"upload.button_processing": "Verarbeitung...",
|
||||
"upload.camera_button": "Foto aufnehmen / Dokument scannen",
|
||||
"upload.download_button": "Herunterladen und verarbeiten",
|
||||
"upload.downloading": "Datei wird von URL heruntergeladen...",
|
||||
"upload.drag_drop": "Dateien hierher ziehen oder zum Durchsuchen klicken",
|
||||
"upload.drop_hint_desktop": "Dateien oder Ordner hierher ziehen oder klicken, um Dateien auszuwählen.",
|
||||
"upload.drop_hint_mobile": "Tippen Sie, um Dateien auszuwählen, oder verwenden Sie die Kamera-Schaltfläche unten.",
|
||||
"upload.error": "Upload fehlgeschlagen",
|
||||
"upload.error_invalid_url": "Ungültiges URL-Format",
|
||||
"upload.error_url_required": "Bitte geben Sie eine URL ein",
|
||||
"upload.file_size_hint": "Maximale Größe: 500 MB pro Datei",
|
||||
"upload.file_types": "Erlaubte Typen: PDF, Office-Dokumente (Word, Excel, PowerPoint usw.), Bilder",
|
||||
"upload.filename_description": "Leer lassen, um den Dateinamen aus der URL zu verwenden",
|
||||
"upload.filename_label": "Dateiname (optional)",
|
||||
"upload.filename_placeholder": "mein-dokument.pdf",
|
||||
"upload.max_size": "Maximale Dateigröße: {size}",
|
||||
"upload.page_title": "Dateien hochladen",
|
||||
"upload.section_device": "Vom Gerät hochladen",
|
||||
"upload.section_url": "Von URL hochladen",
|
||||
"upload.select_file": "Datei auswählen",
|
||||
"upload.success": "Datei erfolgreich hochgeladen",
|
||||
"upload.title": "Dokument hochladen",
|
||||
"upload.uploading": "Wird hochgeladen...",
|
||||
"upload.url_description": "Geben Sie einen direkten Link zu einer Datei ein (PDF, Office-Dokumente oder Bilder)",
|
||||
"upload.url_label": "Datei-URL",
|
||||
"upload.url_placeholder": "https://beispiel.de/dokument.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Η γλώσσα άλλαξε σε {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Ελληνικά",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.upload": "Upload",
|
||||
"nav.files": "Files",
|
||||
"nav.search": "Search",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.help": "Help",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.settings": "Settings",
|
||||
"nav.users": "Users",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.status": "Status",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.help_center": "Help Center",
|
||||
"auth.login": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.profile": "Profile",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.terms": "Terms",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.license": "License",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.version": "Version {version}",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"common.save": "Save",
|
||||
"common.cancel": "Cancel",
|
||||
"common.delete": "Delete",
|
||||
"common.edit": "Edit",
|
||||
"common.close": "Close",
|
||||
"common.confirm": "Confirm",
|
||||
"common.back": "Back",
|
||||
"common.next": "Next",
|
||||
"common.loading": "Loading...",
|
||||
"common.error": "Error",
|
||||
"common.success": "Success",
|
||||
"common.warning": "Warning",
|
||||
"common.info": "Info",
|
||||
"common.yes": "Yes",
|
||||
"common.no": "No",
|
||||
"common.search": "Search",
|
||||
"common.filter": "Filter",
|
||||
"common.reset": "Reset",
|
||||
"common.refresh": "Refresh",
|
||||
"common.download": "Download",
|
||||
"common.actions": "Actions",
|
||||
"common.details": "Details",
|
||||
"common.name": "Name",
|
||||
"common.description": "Description",
|
||||
"common.type": "Type",
|
||||
"common.status": "Status",
|
||||
"common.date": "Date",
|
||||
"common.size": "Size",
|
||||
"common.created": "Created",
|
||||
"common.updated": "Updated",
|
||||
"common.enabled": "Enabled",
|
||||
"common.disabled": "Disabled",
|
||||
"common.active": "Active",
|
||||
"common.inactive": "Inactive",
|
||||
"common.all": "All",
|
||||
"common.none": "None",
|
||||
"common.select": "Select",
|
||||
"common.upload": "Upload",
|
||||
"common.processing": "Processing",
|
||||
"common.completed": "Completed",
|
||||
"common.failed": "Failed",
|
||||
"common.pending": "Pending",
|
||||
"common.retry": "Retry",
|
||||
"common.view": "View",
|
||||
"common.copy": "Copy",
|
||||
"common.copied": "Copied!",
|
||||
"language.selector": "Language",
|
||||
"language.en": "English",
|
||||
"language.de": "Deutsch",
|
||||
"language.fr": "Français",
|
||||
"language.es": "Español",
|
||||
"language.it": "Italiano",
|
||||
"language.pt": "Português",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.zh": "中文",
|
||||
"language.ru": "Русский",
|
||||
"language.changed": "Language changed to {language}",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"files.title": "Files",
|
||||
"files.no_files": "No files found",
|
||||
"files.filename": "Filename",
|
||||
"files.document_title": "Document Title",
|
||||
"files.uploaded": "Uploaded",
|
||||
"files.file_size": "File Size",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.tags": "Tags",
|
||||
"search.title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.no_results": "No results found",
|
||||
"search.results_count": "{count} results found",
|
||||
"settings.title": "Settings",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.configure": "Configure",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"help.title": "Help Center",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.documentation": "Documentation",
|
||||
"help.support": "Support",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.button_processing": "Processing...",
|
||||
"files.page_title": "File Records",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.table_id": "ID",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_empty": "No files found",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.action_details": "View details",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_last": "Last",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.button": "Search",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"help.page_title": "Help Center",
|
||||
"help.heading": "Help Center",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.404_home": "Return Home",
|
||||
"error.500_code": "500",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_home": "Go Home",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.active_label": "Active",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.username_label": "Username",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"status.page_title": "System Status",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.last_check": "Last Check",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.email_label": "Email",
|
||||
"auth.password_label": "Password",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.username_label": "Username",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"language.nb": "Norsk",
|
||||
"language.da": "Dansk",
|
||||
"language.sv": "Svenska",
|
||||
"language.fi": "Suomi",
|
||||
"language.is": "Íslenska",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hu": "Magyar",
|
||||
"language.cs": "Čeština",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.ro": "Română",
|
||||
"language.bg": "Български",
|
||||
"language.uk": "Українська",
|
||||
"language.tr": "Türkçe",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.et": "Eesti",
|
||||
"language.lv": "Latviešu",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.ca": "Català"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Iniciar sesión",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Cerrar sesión",
|
||||
"auth.my_account": "Mi cuenta",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Perfil",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Registrarse",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Acciones",
|
||||
"common.active": "Activo",
|
||||
"common.all": "Todo",
|
||||
"common.back": "Atrás",
|
||||
"common.cancel": "Cancelar",
|
||||
"common.close": "Cerrar",
|
||||
"common.completed": "Completado",
|
||||
"common.confirm": "Confirmar",
|
||||
"common.copied": "¡Copiado!",
|
||||
"common.copy": "Copiar",
|
||||
"common.created": "Creado",
|
||||
"common.date": "Fecha",
|
||||
"common.delete": "Eliminar",
|
||||
"common.description": "Descripción",
|
||||
"common.details": "Detalles",
|
||||
"common.disabled": "Deshabilitado",
|
||||
"common.download": "Descargar",
|
||||
"common.edit": "Editar",
|
||||
"common.enabled": "Habilitado",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Fallido",
|
||||
"common.filter": "Filtrar",
|
||||
"common.inactive": "Inactivo",
|
||||
"common.info": "Información",
|
||||
"common.loading": "Cargando...",
|
||||
"common.name": "Nombre",
|
||||
"common.next": "Siguiente",
|
||||
"common.no": "No",
|
||||
"common.none": "Ninguno",
|
||||
"common.pending": "Pendiente",
|
||||
"common.processing": "Procesando",
|
||||
"common.refresh": "Actualizar",
|
||||
"common.reset": "Restablecer",
|
||||
"common.retry": "Reintentar",
|
||||
"common.save": "Guardar",
|
||||
"common.search": "Buscar",
|
||||
"common.select": "Seleccionar",
|
||||
"common.size": "Tamaño",
|
||||
"common.status": "Estado",
|
||||
"common.success": "Éxito",
|
||||
"common.type": "Tipo",
|
||||
"common.updated": "Actualizado",
|
||||
"common.upload": "Subir",
|
||||
"common.view": "Ver",
|
||||
"common.warning": "Advertencia",
|
||||
"common.yes": "Sí",
|
||||
"cookie.accept": "Entendido",
|
||||
"cookie.notice": "DocuElevate utiliza solo cookies de sesión esenciales necesarias para la autenticación y el funcionamiento del servicio. No se utilizan cookies de seguimiento ni analíticas.",
|
||||
"cookie.notice_label": "Aviso de cookies",
|
||||
"cookie.policy_link": "Política de cookies",
|
||||
"cookie.privacy_link": "Aviso de privacidad",
|
||||
"dashboard.active_integrations": "Integraciones activas",
|
||||
"dashboard.files_this_month": "Archivos este mes",
|
||||
"dashboard.files_today": "Archivos hoy",
|
||||
"dashboard.ocr_processed": "OCR procesados",
|
||||
"dashboard.quick_actions": "Acciones rápidas",
|
||||
"dashboard.recent_activity": "Actividad reciente",
|
||||
"dashboard.storage_targets": "Destinos de almacenamiento",
|
||||
"dashboard.title": "Panel",
|
||||
"dashboard.total_files": "Total de archivos",
|
||||
"dashboard.welcome": "Bienvenido a DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Prohibido",
|
||||
"error.forbidden_message": "No tiene permiso para acceder a esta página.",
|
||||
"error.not_found": "Página no encontrada",
|
||||
"error.not_found_message": "La página que busca no existe.",
|
||||
"error.server_error": "Error interno del servidor",
|
||||
"error.server_error_message": "Algo salió mal. Inténtelo de nuevo más tarde.",
|
||||
"error.unauthorized": "No autorizado",
|
||||
"error.unauthorized_message": "Debe iniciar sesión para acceder a esta página.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Título del documento",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "Tamaño del archivo",
|
||||
"files.filename": "Nombre del archivo",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No se encontraron archivos",
|
||||
"files.ocr_status": "Estado OCR",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Etiquetas",
|
||||
"files.title": "Archivos",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Subido",
|
||||
"footer.attributions": "Atribuciones",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Aviso legal",
|
||||
"footer.license": "Licencia",
|
||||
"footer.navigation": "Navegación del pie de página",
|
||||
"footer.privacy": "Privacidad",
|
||||
"footer.terms": "Términos",
|
||||
"footer.version": "Versión {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentación",
|
||||
"help.faq": "Preguntas frecuentes",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Primeros pasos",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Soporte",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Centro de ayuda",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configurar",
|
||||
"integrations.connect": "Conectar",
|
||||
"integrations.connected": "Conectado",
|
||||
"integrations.disconnect": "Desconectar",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "No conectado",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integraciones",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Idioma cambiado a {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Idioma",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "Acerca de",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Acciones de administración",
|
||||
"nav.admin_menu": "Menú de administración",
|
||||
"nav.api_docs": "Documentación API",
|
||||
"nav.backup_restore": "Copia de seguridad y restauración",
|
||||
"nav.credentials": "Credenciales",
|
||||
"nav.dark_mode": "Modo oscuro",
|
||||
"nav.dashboard": "Panel",
|
||||
"nav.developer_docs": "Documentación para desarrolladores",
|
||||
"nav.duplicates": "Duplicados",
|
||||
"nav.file_manager": "Gestor de archivos",
|
||||
"nav.files": "Archivos",
|
||||
"nav.help": "Ayuda",
|
||||
"nav.help_center": "Centro de ayuda",
|
||||
"nav.integrations": "Integraciones",
|
||||
"nav.light_mode": "Modo claro",
|
||||
"nav.main_navigation": "Navegación principal",
|
||||
"nav.notifications": "Notificaciones",
|
||||
"nav.open_main_menu": "Abrir menú principal",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Diseñador de planes",
|
||||
"nav.pricing": "Precios",
|
||||
"nav.queue_monitor": "Monitor de cola",
|
||||
"nav.scheduled_jobs": "Tareas programadas",
|
||||
"nav.search": "Buscar",
|
||||
"nav.settings": "Configuración",
|
||||
"nav.similarity": "Similitud",
|
||||
"nav.skip_to_content": "Ir al contenido principal",
|
||||
"nav.status": "Estado",
|
||||
"nav.toggle_dark_mode": "Alternar modo oscuro",
|
||||
"nav.toggle_nav": "Alternar menú de navegación",
|
||||
"nav.upload": "Subir",
|
||||
"nav.users": "Usuarios",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Marcar todo como leído",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Marcar como leído",
|
||||
"notifications.no_notifications": "Sin notificaciones",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notificaciones",
|
||||
"notifications.unread_count": "{count} notificaciones no leídas",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Crear pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Editar pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Pipelines de procesamiento",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No se encontraron resultados",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Buscar por nombre, contenido, etiquetas...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} resultados encontrados",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Buscar documentos",
|
||||
"settings.reset_confirm": "¿Está seguro de que desea restablecer esta configuración?",
|
||||
"settings.save_error": "Error al guardar la configuración",
|
||||
"settings.save_success": "Configuración guardada con éxito",
|
||||
"settings.title": "Configuración",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Arrastre archivos aquí o haga clic para buscar",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Error al subir",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Tamaño máximo del archivo: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Seleccionar archivo",
|
||||
"upload.success": "Archivo subido con éxito",
|
||||
"upload.title": "Subir documento",
|
||||
"upload.uploading": "Subiendo...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Keel muudeti keelele {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Eesti",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Kieli vaihdettiin kieleen {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Suomi",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Se connecter",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Se déconnecter",
|
||||
"auth.my_account": "Mon compte",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profil",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "S'inscrire",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Actif",
|
||||
"common.all": "Tout",
|
||||
"common.back": "Retour",
|
||||
"common.cancel": "Annuler",
|
||||
"common.close": "Fermer",
|
||||
"common.completed": "Terminé",
|
||||
"common.confirm": "Confirmer",
|
||||
"common.copied": "Copié !",
|
||||
"common.copy": "Copier",
|
||||
"common.created": "Créé",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Supprimer",
|
||||
"common.description": "Description",
|
||||
"common.details": "Détails",
|
||||
"common.disabled": "Désactivé",
|
||||
"common.download": "Télécharger",
|
||||
"common.edit": "Modifier",
|
||||
"common.enabled": "Activé",
|
||||
"common.error": "Erreur",
|
||||
"common.failed": "Échoué",
|
||||
"common.filter": "Filtrer",
|
||||
"common.inactive": "Inactif",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Chargement...",
|
||||
"common.name": "Nom",
|
||||
"common.next": "Suivant",
|
||||
"common.no": "Non",
|
||||
"common.none": "Aucun",
|
||||
"common.pending": "En attente",
|
||||
"common.processing": "En cours de traitement",
|
||||
"common.refresh": "Actualiser",
|
||||
"common.reset": "Réinitialiser",
|
||||
"common.retry": "Réessayer",
|
||||
"common.save": "Enregistrer",
|
||||
"common.search": "Rechercher",
|
||||
"common.select": "Sélectionner",
|
||||
"common.size": "Taille",
|
||||
"common.status": "Statut",
|
||||
"common.success": "Succès",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Mis à jour",
|
||||
"common.upload": "Téléverser",
|
||||
"common.view": "Voir",
|
||||
"common.warning": "Avertissement",
|
||||
"common.yes": "Oui",
|
||||
"cookie.accept": "Compris",
|
||||
"cookie.notice": "DocuElevate utilise uniquement des cookies de session essentiels nécessaires à l'authentification et au fonctionnement du service. Aucun cookie de suivi ou d'analyse n'est utilisé.",
|
||||
"cookie.notice_label": "Avis relatif aux cookies",
|
||||
"cookie.policy_link": "Politique de cookies",
|
||||
"cookie.privacy_link": "Avis de confidentialité",
|
||||
"dashboard.active_integrations": "Intégrations actives",
|
||||
"dashboard.files_this_month": "Fichiers ce mois-ci",
|
||||
"dashboard.files_today": "Fichiers aujourd'hui",
|
||||
"dashboard.ocr_processed": "OCR traités",
|
||||
"dashboard.quick_actions": "Actions rapides",
|
||||
"dashboard.recent_activity": "Activité récente",
|
||||
"dashboard.storage_targets": "Destinations de stockage",
|
||||
"dashboard.title": "Tableau de bord",
|
||||
"dashboard.total_files": "Total des fichiers",
|
||||
"dashboard.welcome": "Bienvenue sur DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Interdit",
|
||||
"error.forbidden_message": "Vous n'avez pas la permission d'accéder à cette page.",
|
||||
"error.not_found": "Page non trouvée",
|
||||
"error.not_found_message": "La page que vous recherchez n'existe pas.",
|
||||
"error.server_error": "Erreur interne du serveur",
|
||||
"error.server_error_message": "Quelque chose s'est mal passé. Veuillez réessayer plus tard.",
|
||||
"error.unauthorized": "Non autorisé",
|
||||
"error.unauthorized_message": "Vous devez vous connecter pour accéder à cette page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Titre du document",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "Taille du fichier",
|
||||
"files.filename": "Nom du fichier",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "Aucun fichier trouvé",
|
||||
"files.ocr_status": "Statut OCR",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Étiquettes",
|
||||
"files.title": "Fichiers",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Téléversé",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Mentions légales",
|
||||
"footer.license": "Licence",
|
||||
"footer.navigation": "Navigation du pied de page",
|
||||
"footer.privacy": "Confidentialité",
|
||||
"footer.terms": "Conditions",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Questions fréquentes",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Premiers pas",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Centre d'aide",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configurer",
|
||||
"integrations.connect": "Connecter",
|
||||
"integrations.connected": "Connecté",
|
||||
"integrations.disconnect": "Déconnecter",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Non connecté",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Intégrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Langue changée en {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Langue",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "À propos",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Actions admin",
|
||||
"nav.admin_menu": "Menu admin",
|
||||
"nav.api_docs": "Documentation API",
|
||||
"nav.backup_restore": "Sauvegarde et restauration",
|
||||
"nav.credentials": "Identifiants",
|
||||
"nav.dark_mode": "Mode sombre",
|
||||
"nav.dashboard": "Tableau de bord",
|
||||
"nav.developer_docs": "Documentation développeur",
|
||||
"nav.duplicates": "Doublons",
|
||||
"nav.file_manager": "Gestionnaire de fichiers",
|
||||
"nav.files": "Fichiers",
|
||||
"nav.help": "Aide",
|
||||
"nav.help_center": "Centre d'aide",
|
||||
"nav.integrations": "Intégrations",
|
||||
"nav.light_mode": "Mode clair",
|
||||
"nav.main_navigation": "Navigation principale",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Ouvrir le menu principal",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Concepteur de plans",
|
||||
"nav.pricing": "Tarifs",
|
||||
"nav.queue_monitor": "File d'attente",
|
||||
"nav.scheduled_jobs": "Tâches planifiées",
|
||||
"nav.search": "Recherche",
|
||||
"nav.settings": "Paramètres",
|
||||
"nav.similarity": "Similarité",
|
||||
"nav.skip_to_content": "Aller au contenu principal",
|
||||
"nav.status": "Statut",
|
||||
"nav.toggle_dark_mode": "Basculer le mode sombre",
|
||||
"nav.toggle_nav": "Basculer le menu de navigation",
|
||||
"nav.upload": "Téléverser",
|
||||
"nav.users": "Utilisateurs",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Tout marquer comme lu",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Marquer comme lu",
|
||||
"notifications.no_notifications": "Aucune notification",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} notifications non lues",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Créer un pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Modifier le pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Pipelines de traitement",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "Aucun résultat trouvé",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Rechercher par nom, contenu, étiquettes...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} résultats trouvés",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Rechercher des documents",
|
||||
"settings.reset_confirm": "Êtes-vous sûr de vouloir réinitialiser ce paramètre ?",
|
||||
"settings.save_error": "Échec de l'enregistrement du paramètre",
|
||||
"settings.save_success": "Paramètre enregistré avec succès",
|
||||
"settings.title": "Paramètres",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Glissez-déposez vos fichiers ici ou cliquez pour parcourir",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Échec du téléversement",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Taille maximale du fichier : {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Sélectionner un fichier",
|
||||
"upload.success": "Fichier téléversé avec succès",
|
||||
"upload.title": "Téléverser un document",
|
||||
"upload.uploading": "Téléversement en cours...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Athraíodh an teanga go {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Gaeilge",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Jezik je promijenjen na {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Hrvatski",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "A nyelv megváltozott erre: {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Magyar",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Tungumálið var breytt í {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Íslenska",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Accedi",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Esci",
|
||||
"auth.my_account": "Il mio account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profilo",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Registrati",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Azioni",
|
||||
"common.active": "Attivo",
|
||||
"common.all": "Tutto",
|
||||
"common.back": "Indietro",
|
||||
"common.cancel": "Annulla",
|
||||
"common.close": "Chiudi",
|
||||
"common.completed": "Completato",
|
||||
"common.confirm": "Conferma",
|
||||
"common.copied": "Copiato!",
|
||||
"common.copy": "Copia",
|
||||
"common.created": "Creato",
|
||||
"common.date": "Data",
|
||||
"common.delete": "Elimina",
|
||||
"common.description": "Descrizione",
|
||||
"common.details": "Dettagli",
|
||||
"common.disabled": "Disabilitato",
|
||||
"common.download": "Scarica",
|
||||
"common.edit": "Modifica",
|
||||
"common.enabled": "Abilitato",
|
||||
"common.error": "Errore",
|
||||
"common.failed": "Fallito",
|
||||
"common.filter": "Filtra",
|
||||
"common.inactive": "Inattivo",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Caricamento...",
|
||||
"common.name": "Nome",
|
||||
"common.next": "Avanti",
|
||||
"common.no": "No",
|
||||
"common.none": "Nessuno",
|
||||
"common.pending": "In attesa",
|
||||
"common.processing": "In elaborazione",
|
||||
"common.refresh": "Aggiorna",
|
||||
"common.reset": "Reimposta",
|
||||
"common.retry": "Riprova",
|
||||
"common.save": "Salva",
|
||||
"common.search": "Cerca",
|
||||
"common.select": "Seleziona",
|
||||
"common.size": "Dimensione",
|
||||
"common.status": "Stato",
|
||||
"common.success": "Successo",
|
||||
"common.type": "Tipo",
|
||||
"common.updated": "Aggiornato",
|
||||
"common.upload": "Carica",
|
||||
"common.view": "Visualizza",
|
||||
"common.warning": "Avviso",
|
||||
"common.yes": "Sì",
|
||||
"cookie.accept": "Ho capito",
|
||||
"cookie.notice": "DocuElevate utilizza solo cookie di sessione essenziali necessari per l'autenticazione e il funzionamento del servizio. Non vengono utilizzati cookie di tracciamento o analisi.",
|
||||
"cookie.notice_label": "Avviso sui cookie",
|
||||
"cookie.policy_link": "Politica sui cookie",
|
||||
"cookie.privacy_link": "Informativa sulla privacy",
|
||||
"dashboard.active_integrations": "Integrazioni attive",
|
||||
"dashboard.files_this_month": "File questo mese",
|
||||
"dashboard.files_today": "File oggi",
|
||||
"dashboard.ocr_processed": "OCR elaborati",
|
||||
"dashboard.quick_actions": "Azioni rapide",
|
||||
"dashboard.recent_activity": "Attività recente",
|
||||
"dashboard.storage_targets": "Destinazioni di archiviazione",
|
||||
"dashboard.title": "Cruscotto",
|
||||
"dashboard.total_files": "File totali",
|
||||
"dashboard.welcome": "Benvenuto su DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Vietato",
|
||||
"error.forbidden_message": "Non hai il permesso di accedere a questa pagina.",
|
||||
"error.not_found": "Pagina non trovata",
|
||||
"error.not_found_message": "La pagina che stai cercando non esiste.",
|
||||
"error.server_error": "Errore interno del server",
|
||||
"error.server_error_message": "Qualcosa è andato storto. Riprova più tardi.",
|
||||
"error.unauthorized": "Non autorizzato",
|
||||
"error.unauthorized_message": "Devi accedere per visualizzare questa pagina.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Titolo del documento",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "Dimensione del file",
|
||||
"files.filename": "Nome del file",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "Nessun file trovato",
|
||||
"files.ocr_status": "Stato OCR",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tag",
|
||||
"files.title": "File",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Caricato",
|
||||
"footer.attributions": "Attribuzioni",
|
||||
"footer.cookies": "Cookie",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Note legali",
|
||||
"footer.license": "Licenza",
|
||||
"footer.navigation": "Navigazione a piè di pagina",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Termini",
|
||||
"footer.version": "Versione {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentazione",
|
||||
"help.faq": "Domande frequenti",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Per iniziare",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Supporto",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Centro assistenza",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configura",
|
||||
"integrations.connect": "Connetti",
|
||||
"integrations.connected": "Connesso",
|
||||
"integrations.disconnect": "Disconnetti",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Non connesso",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrazioni",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Lingua cambiata in {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Lingua",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "Informazioni",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Azioni admin",
|
||||
"nav.admin_menu": "Menu admin",
|
||||
"nav.api_docs": "Documentazione API",
|
||||
"nav.backup_restore": "Backup e ripristino",
|
||||
"nav.credentials": "Credenziali",
|
||||
"nav.dark_mode": "Modalità scura",
|
||||
"nav.dashboard": "Cruscotto",
|
||||
"nav.developer_docs": "Documentazione sviluppatore",
|
||||
"nav.duplicates": "Duplicati",
|
||||
"nav.file_manager": "Gestore file",
|
||||
"nav.files": "File",
|
||||
"nav.help": "Aiuto",
|
||||
"nav.help_center": "Centro assistenza",
|
||||
"nav.integrations": "Integrazioni",
|
||||
"nav.light_mode": "Modalità chiara",
|
||||
"nav.main_navigation": "Navigazione principale",
|
||||
"nav.notifications": "Notifiche",
|
||||
"nav.open_main_menu": "Apri menu principale",
|
||||
"nav.pipelines": "Pipeline",
|
||||
"nav.plan_designer": "Designer dei piani",
|
||||
"nav.pricing": "Prezzi",
|
||||
"nav.queue_monitor": "Monitor coda",
|
||||
"nav.scheduled_jobs": "Attività pianificate",
|
||||
"nav.search": "Cerca",
|
||||
"nav.settings": "Impostazioni",
|
||||
"nav.similarity": "Similarità",
|
||||
"nav.skip_to_content": "Vai al contenuto principale",
|
||||
"nav.status": "Stato",
|
||||
"nav.toggle_dark_mode": "Attiva/disattiva modalità scura",
|
||||
"nav.toggle_nav": "Attiva/disattiva menu di navigazione",
|
||||
"nav.upload": "Carica",
|
||||
"nav.users": "Utenti",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Segna tutto come letto",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Segna come letto",
|
||||
"notifications.no_notifications": "Nessuna notifica",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifiche",
|
||||
"notifications.unread_count": "{count} notifiche non lette",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Crea pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Modifica pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Pipeline di elaborazione",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "Nessun risultato trovato",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Cerca per nome, contenuto, tag...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} risultati trovati",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Cerca documenti",
|
||||
"settings.reset_confirm": "Sei sicuro di voler reimpostare questa impostazione?",
|
||||
"settings.save_error": "Salvataggio impostazione fallito",
|
||||
"settings.save_success": "Impostazione salvata con successo",
|
||||
"settings.title": "Impostazioni",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Trascina i file qui o fai clic per sfogliare",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Caricamento fallito",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Dimensione massima del file: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Seleziona file",
|
||||
"upload.success": "File caricato con successo",
|
||||
"upload.title": "Carica documento",
|
||||
"upload.uploading": "Caricamento in corso...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "D'Sprooch gouf op {language} geännert",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Lëtzebuergesch",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Kalba pakeista į {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Lietuvių",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Valoda tika nomainīta uz {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Latviešu",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Språket ble endret til {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Norsk",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Inloggen",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Uitloggen",
|
||||
"auth.my_account": "Mijn account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profiel",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Registreren",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Acties",
|
||||
"common.active": "Actief",
|
||||
"common.all": "Alles",
|
||||
"common.back": "Terug",
|
||||
"common.cancel": "Annuleren",
|
||||
"common.close": "Sluiten",
|
||||
"common.completed": "Voltooid",
|
||||
"common.confirm": "Bevestigen",
|
||||
"common.copied": "Gekopieerd!",
|
||||
"common.copy": "Kopiëren",
|
||||
"common.created": "Aangemaakt",
|
||||
"common.date": "Datum",
|
||||
"common.delete": "Verwijderen",
|
||||
"common.description": "Beschrijving",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Uitgeschakeld",
|
||||
"common.download": "Downloaden",
|
||||
"common.edit": "Bewerken",
|
||||
"common.enabled": "Ingeschakeld",
|
||||
"common.error": "Fout",
|
||||
"common.failed": "Mislukt",
|
||||
"common.filter": "Filteren",
|
||||
"common.inactive": "Inactief",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Laden...",
|
||||
"common.name": "Naam",
|
||||
"common.next": "Volgende",
|
||||
"common.no": "Nee",
|
||||
"common.none": "Geen",
|
||||
"common.pending": "In afwachting",
|
||||
"common.processing": "Verwerken",
|
||||
"common.refresh": "Vernieuwen",
|
||||
"common.reset": "Herstellen",
|
||||
"common.retry": "Opnieuw proberen",
|
||||
"common.save": "Opslaan",
|
||||
"common.search": "Zoeken",
|
||||
"common.select": "Selecteren",
|
||||
"common.size": "Grootte",
|
||||
"common.status": "Status",
|
||||
"common.success": "Succes",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Bijgewerkt",
|
||||
"common.upload": "Uploaden",
|
||||
"common.view": "Bekijken",
|
||||
"common.warning": "Waarschuwing",
|
||||
"common.yes": "Ja",
|
||||
"cookie.accept": "Begrepen",
|
||||
"cookie.notice": "DocuElevate gebruikt alleen essentiële sessiecookies die nodig zijn voor authenticatie en werking van de service. Er worden geen tracking- of analysecookies gebruikt.",
|
||||
"cookie.notice_label": "Cookiemelding",
|
||||
"cookie.policy_link": "Cookiebeleid",
|
||||
"cookie.privacy_link": "Privacyverklaring",
|
||||
"dashboard.active_integrations": "Actieve integraties",
|
||||
"dashboard.files_this_month": "Bestanden deze maand",
|
||||
"dashboard.files_today": "Bestanden vandaag",
|
||||
"dashboard.ocr_processed": "OCR verwerkt",
|
||||
"dashboard.quick_actions": "Snelle acties",
|
||||
"dashboard.recent_activity": "Recente activiteit",
|
||||
"dashboard.storage_targets": "Opslagdoelen",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Totaal bestanden",
|
||||
"dashboard.welcome": "Welkom bij DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Verboden",
|
||||
"error.forbidden_message": "U heeft geen toestemming om deze pagina te openen.",
|
||||
"error.not_found": "Pagina niet gevonden",
|
||||
"error.not_found_message": "De pagina die u zoekt bestaat niet.",
|
||||
"error.server_error": "Interne serverfout",
|
||||
"error.server_error_message": "Er is iets misgegaan. Probeer het later opnieuw.",
|
||||
"error.unauthorized": "Niet geautoriseerd",
|
||||
"error.unauthorized_message": "U moet inloggen om deze pagina te openen.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Documenttitel",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "Bestandsgrootte",
|
||||
"files.filename": "Bestandsnaam",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "Geen bestanden gevonden",
|
||||
"files.ocr_status": "OCR-status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Bestanden",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Geüpload",
|
||||
"footer.attributions": "Attributies",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Colofon",
|
||||
"footer.license": "Licentie",
|
||||
"footer.navigation": "Voettekstnavigatie",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Voorwaarden",
|
||||
"footer.version": "Versie {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentatie",
|
||||
"help.faq": "Veelgestelde vragen",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Aan de slag",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Ondersteuning",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Helpcentrum",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configureren",
|
||||
"integrations.connect": "Verbinden",
|
||||
"integrations.connected": "Verbonden",
|
||||
"integrations.disconnect": "Verbreken",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Niet verbonden",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integraties",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Taal gewijzigd naar {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Taal",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "Over ons",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin-acties",
|
||||
"nav.admin_menu": "Admin-menu",
|
||||
"nav.api_docs": "API-documentatie",
|
||||
"nav.backup_restore": "Back-up en herstel",
|
||||
"nav.credentials": "Referenties",
|
||||
"nav.dark_mode": "Donkere modus",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Ontwikkelaarsdocumentatie",
|
||||
"nav.duplicates": "Duplicaten",
|
||||
"nav.file_manager": "Bestandsbeheer",
|
||||
"nav.files": "Bestanden",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Helpcentrum",
|
||||
"nav.integrations": "Integraties",
|
||||
"nav.light_mode": "Lichte modus",
|
||||
"nav.main_navigation": "Hoofdnavigatie",
|
||||
"nav.notifications": "Meldingen",
|
||||
"nav.open_main_menu": "Hoofdmenu openen",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Planontwerper",
|
||||
"nav.pricing": "Prijzen",
|
||||
"nav.queue_monitor": "Wachtrijmonitor",
|
||||
"nav.scheduled_jobs": "Geplande taken",
|
||||
"nav.search": "Zoeken",
|
||||
"nav.settings": "Instellingen",
|
||||
"nav.similarity": "Gelijkenis",
|
||||
"nav.skip_to_content": "Ga naar hoofdinhoud",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Donkere modus schakelen",
|
||||
"nav.toggle_nav": "Navigatiemenu schakelen",
|
||||
"nav.upload": "Uploaden",
|
||||
"nav.users": "Gebruikers",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Alles als gelezen markeren",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Markeren als gelezen",
|
||||
"notifications.no_notifications": "Geen meldingen",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Meldingen",
|
||||
"notifications.unread_count": "{count} ongelezen meldingen",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Pipeline maken",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Pipeline bewerken",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Verwerkingspipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "Geen resultaten gevonden",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Zoeken op naam, inhoud, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} resultaten gevonden",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Documenten zoeken",
|
||||
"settings.reset_confirm": "Weet u zeker dat u deze instelling wilt herstellen?",
|
||||
"settings.save_error": "Instelling opslaan mislukt",
|
||||
"settings.save_success": "Instelling succesvol opgeslagen",
|
||||
"settings.title": "Instellingen",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Sleep bestanden hierheen of klik om te bladeren",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload mislukt",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximale bestandsgrootte: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Bestand selecteren",
|
||||
"upload.success": "Bestand succesvol geüpload",
|
||||
"upload.title": "Document uploaden",
|
||||
"upload.uploading": "Uploaden...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Zaloguj się",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Wyloguj się",
|
||||
"auth.my_account": "Moje konto",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profil",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Zarejestruj się",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Akcje",
|
||||
"common.active": "Aktywny",
|
||||
"common.all": "Wszystko",
|
||||
"common.back": "Wstecz",
|
||||
"common.cancel": "Anuluj",
|
||||
"common.close": "Zamknij",
|
||||
"common.completed": "Zakończono",
|
||||
"common.confirm": "Potwierdź",
|
||||
"common.copied": "Skopiowano!",
|
||||
"common.copy": "Kopiuj",
|
||||
"common.created": "Utworzono",
|
||||
"common.date": "Data",
|
||||
"common.delete": "Usuń",
|
||||
"common.description": "Opis",
|
||||
"common.details": "Szczegóły",
|
||||
"common.disabled": "Wyłączony",
|
||||
"common.download": "Pobierz",
|
||||
"common.edit": "Edytuj",
|
||||
"common.enabled": "Włączony",
|
||||
"common.error": "Błąd",
|
||||
"common.failed": "Nieudane",
|
||||
"common.filter": "Filtruj",
|
||||
"common.inactive": "Nieaktywny",
|
||||
"common.info": "Informacja",
|
||||
"common.loading": "Ładowanie...",
|
||||
"common.name": "Nazwa",
|
||||
"common.next": "Dalej",
|
||||
"common.no": "Nie",
|
||||
"common.none": "Brak",
|
||||
"common.pending": "Oczekujące",
|
||||
"common.processing": "Przetwarzanie",
|
||||
"common.refresh": "Odśwież",
|
||||
"common.reset": "Resetuj",
|
||||
"common.retry": "Ponów",
|
||||
"common.save": "Zapisz",
|
||||
"common.search": "Szukaj",
|
||||
"common.select": "Wybierz",
|
||||
"common.size": "Rozmiar",
|
||||
"common.status": "Status",
|
||||
"common.success": "Sukces",
|
||||
"common.type": "Typ",
|
||||
"common.updated": "Zaktualizowano",
|
||||
"common.upload": "Prześlij",
|
||||
"common.view": "Wyświetl",
|
||||
"common.warning": "Ostrzeżenie",
|
||||
"common.yes": "Tak",
|
||||
"cookie.accept": "Rozumiem",
|
||||
"cookie.notice": "DocuElevate używa wyłącznie niezbędnych plików cookie sesji wymaganych do uwierzytelniania i działania usługi. Nie są używane pliki cookie śledzące ani analityczne.",
|
||||
"cookie.notice_label": "Informacja o plikach cookie",
|
||||
"cookie.policy_link": "Polityka plików cookie",
|
||||
"cookie.privacy_link": "Informacja o prywatności",
|
||||
"dashboard.active_integrations": "Aktywne integracje",
|
||||
"dashboard.files_this_month": "Pliki w tym miesiącu",
|
||||
"dashboard.files_today": "Pliki dzisiaj",
|
||||
"dashboard.ocr_processed": "OCR przetworzone",
|
||||
"dashboard.quick_actions": "Szybkie akcje",
|
||||
"dashboard.recent_activity": "Ostatnia aktywność",
|
||||
"dashboard.storage_targets": "Cele przechowywania",
|
||||
"dashboard.title": "Pulpit",
|
||||
"dashboard.total_files": "Pliki ogółem",
|
||||
"dashboard.welcome": "Witamy w DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Zabroniono",
|
||||
"error.forbidden_message": "Nie masz uprawnień do dostępu do tej strony.",
|
||||
"error.not_found": "Nie znaleziono strony",
|
||||
"error.not_found_message": "Szukana strona nie istnieje.",
|
||||
"error.server_error": "Wewnętrzny błąd serwera",
|
||||
"error.server_error_message": "Coś poszło nie tak. Spróbuj ponownie później.",
|
||||
"error.unauthorized": "Brak autoryzacji",
|
||||
"error.unauthorized_message": "Musisz się zalogować, aby uzyskać dostęp do tej strony.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Tytuł dokumentu",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "Rozmiar pliku",
|
||||
"files.filename": "Nazwa pliku",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "Nie znaleziono plików",
|
||||
"files.ocr_status": "Status OCR",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tagi",
|
||||
"files.title": "Pliki",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Przesłano",
|
||||
"footer.attributions": "Atrybuty",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Impressum",
|
||||
"footer.license": "Licencja",
|
||||
"footer.navigation": "Nawigacja stopki",
|
||||
"footer.privacy": "Prywatność",
|
||||
"footer.terms": "Regulamin",
|
||||
"footer.version": "Wersja {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Dokumentacja",
|
||||
"help.faq": "Często zadawane pytania",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Pierwsze kroki",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Wsparcie",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Centrum pomocy",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Konfiguruj",
|
||||
"integrations.connect": "Połącz",
|
||||
"integrations.connected": "Połączono",
|
||||
"integrations.disconnect": "Rozłącz",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Nie połączono",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integracje",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Język zmieniony na {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Język",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "O nas",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Akcje administratora",
|
||||
"nav.admin_menu": "Menu administratora",
|
||||
"nav.api_docs": "Dokumentacja API",
|
||||
"nav.backup_restore": "Kopia zapasowa i przywracanie",
|
||||
"nav.credentials": "Poświadczenia",
|
||||
"nav.dark_mode": "Tryb ciemny",
|
||||
"nav.dashboard": "Pulpit",
|
||||
"nav.developer_docs": "Dokumentacja dla programistów",
|
||||
"nav.duplicates": "Duplikaty",
|
||||
"nav.file_manager": "Menedżer plików",
|
||||
"nav.files": "Pliki",
|
||||
"nav.help": "Pomoc",
|
||||
"nav.help_center": "Centrum pomocy",
|
||||
"nav.integrations": "Integracje",
|
||||
"nav.light_mode": "Tryb jasny",
|
||||
"nav.main_navigation": "Nawigacja główna",
|
||||
"nav.notifications": "Powiadomienia",
|
||||
"nav.open_main_menu": "Otwórz menu główne",
|
||||
"nav.pipelines": "Potoki",
|
||||
"nav.plan_designer": "Projektant planów",
|
||||
"nav.pricing": "Cennik",
|
||||
"nav.queue_monitor": "Monitor kolejki",
|
||||
"nav.scheduled_jobs": "Zaplanowane zadania",
|
||||
"nav.search": "Szukaj",
|
||||
"nav.settings": "Ustawienia",
|
||||
"nav.similarity": "Podobieństwo",
|
||||
"nav.skip_to_content": "Przejdź do treści głównej",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Przełącz tryb ciemny",
|
||||
"nav.toggle_nav": "Przełącz menu nawigacji",
|
||||
"nav.upload": "Prześlij",
|
||||
"nav.users": "Użytkownicy",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Oznacz wszystkie jako przeczytane",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Oznacz jako przeczytane",
|
||||
"notifications.no_notifications": "Brak powiadomień",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Powiadomienia",
|
||||
"notifications.unread_count": "{count} nieprzeczytanych powiadomień",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Utwórz potok",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edytuj potok",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Potoki przetwarzania",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "Nie znaleziono wyników",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Szukaj wg nazwy, treści, tagów...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "Znaleziono {count} wyników",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Szukaj dokumentów",
|
||||
"settings.reset_confirm": "Czy na pewno chcesz zresetować to ustawienie?",
|
||||
"settings.save_error": "Nie udało się zapisać ustawienia",
|
||||
"settings.save_success": "Ustawienie zapisane pomyślnie",
|
||||
"settings.title": "Ustawienia",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Przeciągnij pliki tutaj lub kliknij, aby przeglądać",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Przesyłanie nie powiodło się",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maksymalny rozmiar pliku: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Wybierz plik",
|
||||
"upload.success": "Plik przesłany pomyślnie",
|
||||
"upload.title": "Prześlij dokument",
|
||||
"upload.uploading": "Przesyłanie...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Iniciar sessão",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Terminar sessão",
|
||||
"auth.my_account": "A minha conta",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Perfil",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Registar",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Ações",
|
||||
"common.active": "Ativo",
|
||||
"common.all": "Tudo",
|
||||
"common.back": "Voltar",
|
||||
"common.cancel": "Cancelar",
|
||||
"common.close": "Fechar",
|
||||
"common.completed": "Concluído",
|
||||
"common.confirm": "Confirmar",
|
||||
"common.copied": "Copiado!",
|
||||
"common.copy": "Copiar",
|
||||
"common.created": "Criado",
|
||||
"common.date": "Data",
|
||||
"common.delete": "Eliminar",
|
||||
"common.description": "Descrição",
|
||||
"common.details": "Detalhes",
|
||||
"common.disabled": "Desativado",
|
||||
"common.download": "Descarregar",
|
||||
"common.edit": "Editar",
|
||||
"common.enabled": "Ativado",
|
||||
"common.error": "Erro",
|
||||
"common.failed": "Falhado",
|
||||
"common.filter": "Filtrar",
|
||||
"common.inactive": "Inativo",
|
||||
"common.info": "Informação",
|
||||
"common.loading": "A carregar...",
|
||||
"common.name": "Nome",
|
||||
"common.next": "Seguinte",
|
||||
"common.no": "Não",
|
||||
"common.none": "Nenhum",
|
||||
"common.pending": "Pendente",
|
||||
"common.processing": "A processar",
|
||||
"common.refresh": "Atualizar",
|
||||
"common.reset": "Repor",
|
||||
"common.retry": "Tentar novamente",
|
||||
"common.save": "Guardar",
|
||||
"common.search": "Pesquisar",
|
||||
"common.select": "Selecionar",
|
||||
"common.size": "Tamanho",
|
||||
"common.status": "Estado",
|
||||
"common.success": "Sucesso",
|
||||
"common.type": "Tipo",
|
||||
"common.updated": "Atualizado",
|
||||
"common.upload": "Carregar",
|
||||
"common.view": "Ver",
|
||||
"common.warning": "Aviso",
|
||||
"common.yes": "Sim",
|
||||
"cookie.accept": "Entendido",
|
||||
"cookie.notice": "O DocuElevate utiliza apenas cookies de sessão essenciais necessários para a autenticação e o funcionamento do serviço. Não são utilizados cookies de rastreamento ou analíticos.",
|
||||
"cookie.notice_label": "Aviso de cookies",
|
||||
"cookie.policy_link": "Política de cookies",
|
||||
"cookie.privacy_link": "Aviso de privacidade",
|
||||
"dashboard.active_integrations": "Integrações ativas",
|
||||
"dashboard.files_this_month": "Ficheiros este mês",
|
||||
"dashboard.files_today": "Ficheiros hoje",
|
||||
"dashboard.ocr_processed": "OCR processados",
|
||||
"dashboard.quick_actions": "Ações rápidas",
|
||||
"dashboard.recent_activity": "Atividade recente",
|
||||
"dashboard.storage_targets": "Destinos de armazenamento",
|
||||
"dashboard.title": "Painel",
|
||||
"dashboard.total_files": "Total de ficheiros",
|
||||
"dashboard.welcome": "Bem-vindo ao DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Proibido",
|
||||
"error.forbidden_message": "Não tem permissão para aceder a esta página.",
|
||||
"error.not_found": "Página não encontrada",
|
||||
"error.not_found_message": "A página que procura não existe.",
|
||||
"error.server_error": "Erro interno do servidor",
|
||||
"error.server_error_message": "Algo correu mal. Tente novamente mais tarde.",
|
||||
"error.unauthorized": "Não autorizado",
|
||||
"error.unauthorized_message": "Precisa de iniciar sessão para aceder a esta página.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Título do documento",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "Tamanho do ficheiro",
|
||||
"files.filename": "Nome do ficheiro",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "Nenhum ficheiro encontrado",
|
||||
"files.ocr_status": "Estado OCR",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Etiquetas",
|
||||
"files.title": "Ficheiros",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Carregado",
|
||||
"footer.attributions": "Atribuições",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Aviso legal",
|
||||
"footer.license": "Licença",
|
||||
"footer.navigation": "Navegação do rodapé",
|
||||
"footer.privacy": "Privacidade",
|
||||
"footer.terms": "Termos",
|
||||
"footer.version": "Versão {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentação",
|
||||
"help.faq": "Perguntas frequentes",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Primeiros passos",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Suporte",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Centro de ajuda",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configurar",
|
||||
"integrations.connect": "Ligar",
|
||||
"integrations.connected": "Ligado",
|
||||
"integrations.disconnect": "Desligar",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Não ligado",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrações",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Idioma alterado para {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Idioma",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "Sobre",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Ações de administração",
|
||||
"nav.admin_menu": "Menu de administração",
|
||||
"nav.api_docs": "Documentação API",
|
||||
"nav.backup_restore": "Cópia de segurança e restauro",
|
||||
"nav.credentials": "Credenciais",
|
||||
"nav.dark_mode": "Modo escuro",
|
||||
"nav.dashboard": "Painel",
|
||||
"nav.developer_docs": "Documentação para programadores",
|
||||
"nav.duplicates": "Duplicados",
|
||||
"nav.file_manager": "Gestor de ficheiros",
|
||||
"nav.files": "Ficheiros",
|
||||
"nav.help": "Ajuda",
|
||||
"nav.help_center": "Centro de ajuda",
|
||||
"nav.integrations": "Integrações",
|
||||
"nav.light_mode": "Modo claro",
|
||||
"nav.main_navigation": "Navegação principal",
|
||||
"nav.notifications": "Notificações",
|
||||
"nav.open_main_menu": "Abrir menu principal",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Designer de planos",
|
||||
"nav.pricing": "Preços",
|
||||
"nav.queue_monitor": "Monitor de fila",
|
||||
"nav.scheduled_jobs": "Tarefas agendadas",
|
||||
"nav.search": "Pesquisar",
|
||||
"nav.settings": "Definições",
|
||||
"nav.similarity": "Similaridade",
|
||||
"nav.skip_to_content": "Ir para o conteúdo principal",
|
||||
"nav.status": "Estado",
|
||||
"nav.toggle_dark_mode": "Alternar modo escuro",
|
||||
"nav.toggle_nav": "Alternar menu de navegação",
|
||||
"nav.upload": "Carregar",
|
||||
"nav.users": "Utilizadores",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Marcar todas como lidas",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Marcar como lida",
|
||||
"notifications.no_notifications": "Sem notificações",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notificações",
|
||||
"notifications.unread_count": "{count} notificações por ler",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Criar pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Editar pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Pipelines de processamento",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "Nenhum resultado encontrado",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Pesquisar por nome, conteúdo, etiquetas...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} resultados encontrados",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Pesquisar documentos",
|
||||
"settings.reset_confirm": "Tem a certeza de que pretende repor esta definição?",
|
||||
"settings.save_error": "Falha ao guardar definição",
|
||||
"settings.save_success": "Definição guardada com sucesso",
|
||||
"settings.title": "Definições",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Arraste ficheiros para aqui ou clique para procurar",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Falha ao carregar",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Tamanho máximo do ficheiro: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Selecionar ficheiro",
|
||||
"upload.success": "Ficheiro carregado com sucesso",
|
||||
"upload.title": "Carregar documento",
|
||||
"upload.uploading": "A carregar...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Limba a fost schimbată în {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Română",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Войти",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Выйти",
|
||||
"auth.my_account": "Мой аккаунт",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Профиль",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Регистрация",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Действия",
|
||||
"common.active": "Активно",
|
||||
"common.all": "Все",
|
||||
"common.back": "Назад",
|
||||
"common.cancel": "Отмена",
|
||||
"common.close": "Закрыть",
|
||||
"common.completed": "Завершено",
|
||||
"common.confirm": "Подтвердить",
|
||||
"common.copied": "Скопировано!",
|
||||
"common.copy": "Копировать",
|
||||
"common.created": "Создано",
|
||||
"common.date": "Дата",
|
||||
"common.delete": "Удалить",
|
||||
"common.description": "Описание",
|
||||
"common.details": "Подробности",
|
||||
"common.disabled": "Отключено",
|
||||
"common.download": "Скачать",
|
||||
"common.edit": "Редактировать",
|
||||
"common.enabled": "Включено",
|
||||
"common.error": "Ошибка",
|
||||
"common.failed": "Ошибка",
|
||||
"common.filter": "Фильтр",
|
||||
"common.inactive": "Неактивно",
|
||||
"common.info": "Информация",
|
||||
"common.loading": "Загрузка...",
|
||||
"common.name": "Название",
|
||||
"common.next": "Далее",
|
||||
"common.no": "Нет",
|
||||
"common.none": "Нет",
|
||||
"common.pending": "В ожидании",
|
||||
"common.processing": "Обработка",
|
||||
"common.refresh": "Обновить",
|
||||
"common.reset": "Сбросить",
|
||||
"common.retry": "Повторить",
|
||||
"common.save": "Сохранить",
|
||||
"common.search": "Поиск",
|
||||
"common.select": "Выбрать",
|
||||
"common.size": "Размер",
|
||||
"common.status": "Статус",
|
||||
"common.success": "Успешно",
|
||||
"common.type": "Тип",
|
||||
"common.updated": "Обновлено",
|
||||
"common.upload": "Загрузить",
|
||||
"common.view": "Просмотр",
|
||||
"common.warning": "Предупреждение",
|
||||
"common.yes": "Да",
|
||||
"cookie.accept": "Понятно",
|
||||
"cookie.notice": "DocuElevate использует только необходимые сессионные файлы cookie для аутентификации и работы сервиса. Файлы cookie для отслеживания и аналитики не используются.",
|
||||
"cookie.notice_label": "Уведомление о файлах cookie",
|
||||
"cookie.policy_link": "Политика файлов cookie",
|
||||
"cookie.privacy_link": "Уведомление о конфиденциальности",
|
||||
"dashboard.active_integrations": "Активные интеграции",
|
||||
"dashboard.files_this_month": "Файлы за месяц",
|
||||
"dashboard.files_today": "Файлы сегодня",
|
||||
"dashboard.ocr_processed": "OCR обработано",
|
||||
"dashboard.quick_actions": "Быстрые действия",
|
||||
"dashboard.recent_activity": "Последняя активность",
|
||||
"dashboard.storage_targets": "Хранилища",
|
||||
"dashboard.title": "Панель управления",
|
||||
"dashboard.total_files": "Всего файлов",
|
||||
"dashboard.welcome": "Добро пожаловать в DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Доступ запрещён",
|
||||
"error.forbidden_message": "У вас нет прав для доступа к этой странице.",
|
||||
"error.not_found": "Страница не найдена",
|
||||
"error.not_found_message": "Запрашиваемая страница не существует.",
|
||||
"error.server_error": "Внутренняя ошибка сервера",
|
||||
"error.server_error_message": "Что-то пошло не так. Пожалуйста, попробуйте позже.",
|
||||
"error.unauthorized": "Не авторизован",
|
||||
"error.unauthorized_message": "Для доступа к этой странице необходимо войти в систему.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Название документа",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "Размер файла",
|
||||
"files.filename": "Имя файла",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "Файлы не найдены",
|
||||
"files.ocr_status": "Статус OCR",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Теги",
|
||||
"files.title": "Файлы",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Загружено",
|
||||
"footer.attributions": "Атрибуции",
|
||||
"footer.cookies": "Файлы cookie",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Выходные данные",
|
||||
"footer.license": "Лицензия",
|
||||
"footer.navigation": "Навигация подвала",
|
||||
"footer.privacy": "Конфиденциальность",
|
||||
"footer.terms": "Условия",
|
||||
"footer.version": "Версия {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Документация",
|
||||
"help.faq": "Часто задаваемые вопросы",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Начало работы",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Поддержка",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Центр помощи",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Настроить",
|
||||
"integrations.connect": "Подключить",
|
||||
"integrations.connected": "Подключено",
|
||||
"integrations.disconnect": "Отключить",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Не подключено",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Интеграции",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Язык изменён на {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Язык",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "О нас",
|
||||
"nav.admin": "Админ",
|
||||
"nav.admin_actions": "Действия администратора",
|
||||
"nav.admin_menu": "Меню администратора",
|
||||
"nav.api_docs": "Документация API",
|
||||
"nav.backup_restore": "Резервное копирование и восстановление",
|
||||
"nav.credentials": "Учётные данные",
|
||||
"nav.dark_mode": "Тёмная тема",
|
||||
"nav.dashboard": "Панель управления",
|
||||
"nav.developer_docs": "Документация для разработчиков",
|
||||
"nav.duplicates": "Дубликаты",
|
||||
"nav.file_manager": "Менеджер файлов",
|
||||
"nav.files": "Файлы",
|
||||
"nav.help": "Помощь",
|
||||
"nav.help_center": "Центр помощи",
|
||||
"nav.integrations": "Интеграции",
|
||||
"nav.light_mode": "Светлая тема",
|
||||
"nav.main_navigation": "Основная навигация",
|
||||
"nav.notifications": "Уведомления",
|
||||
"nav.open_main_menu": "Открыть главное меню",
|
||||
"nav.pipelines": "Конвейеры",
|
||||
"nav.plan_designer": "Конструктор планов",
|
||||
"nav.pricing": "Цены",
|
||||
"nav.queue_monitor": "Монитор очереди",
|
||||
"nav.scheduled_jobs": "Запланированные задачи",
|
||||
"nav.search": "Поиск",
|
||||
"nav.settings": "Настройки",
|
||||
"nav.similarity": "Сходство",
|
||||
"nav.skip_to_content": "Перейти к основному содержанию",
|
||||
"nav.status": "Статус",
|
||||
"nav.toggle_dark_mode": "Переключить тёмную тему",
|
||||
"nav.toggle_nav": "Переключить меню навигации",
|
||||
"nav.upload": "Загрузить",
|
||||
"nav.users": "Пользователи",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Отметить все как прочитанные",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Отметить как прочитанное",
|
||||
"notifications.no_notifications": "Нет уведомлений",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Уведомления",
|
||||
"notifications.unread_count": "{count} непрочитанных уведомлений",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Создать конвейер",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Редактировать конвейер",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Конвейеры обработки",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "Результаты не найдены",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Поиск по имени, содержимому, тегам...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "Найдено результатов: {count}",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Поиск документов",
|
||||
"settings.reset_confirm": "Вы уверены, что хотите сбросить эту настройку?",
|
||||
"settings.save_error": "Не удалось сохранить настройку",
|
||||
"settings.save_success": "Настройка сохранена",
|
||||
"settings.title": "Настройки",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Перетащите файлы сюда или нажмите для выбора",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Ошибка загрузки",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Максимальный размер файла: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Выбрать файл",
|
||||
"upload.success": "Файл успешно загружен",
|
||||
"upload.title": "Загрузить документ",
|
||||
"upload.uploading": "Загрузка...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Jazyk bol zmenený na {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Slovenčina",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Jezik je bil spremenjen na {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Slovenščina",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Språket ändrades till {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Svenska",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Dil {language} olarak değiştirildi",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Türkçe",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "Log In",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "Log Out",
|
||||
"auth.my_account": "My Account",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "Profile",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "Sign Up",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "Actions",
|
||||
"common.active": "Active",
|
||||
"common.all": "All",
|
||||
"common.back": "Back",
|
||||
"common.cancel": "Cancel",
|
||||
"common.close": "Close",
|
||||
"common.completed": "Completed",
|
||||
"common.confirm": "Confirm",
|
||||
"common.copied": "Copied!",
|
||||
"common.copy": "Copy",
|
||||
"common.created": "Created",
|
||||
"common.date": "Date",
|
||||
"common.delete": "Delete",
|
||||
"common.description": "Description",
|
||||
"common.details": "Details",
|
||||
"common.disabled": "Disabled",
|
||||
"common.download": "Download",
|
||||
"common.edit": "Edit",
|
||||
"common.enabled": "Enabled",
|
||||
"common.error": "Error",
|
||||
"common.failed": "Failed",
|
||||
"common.filter": "Filter",
|
||||
"common.inactive": "Inactive",
|
||||
"common.info": "Info",
|
||||
"common.loading": "Loading...",
|
||||
"common.name": "Name",
|
||||
"common.next": "Next",
|
||||
"common.no": "No",
|
||||
"common.none": "None",
|
||||
"common.pending": "Pending",
|
||||
"common.processing": "Processing",
|
||||
"common.refresh": "Refresh",
|
||||
"common.reset": "Reset",
|
||||
"common.retry": "Retry",
|
||||
"common.save": "Save",
|
||||
"common.search": "Search",
|
||||
"common.select": "Select",
|
||||
"common.size": "Size",
|
||||
"common.status": "Status",
|
||||
"common.success": "Success",
|
||||
"common.type": "Type",
|
||||
"common.updated": "Updated",
|
||||
"common.upload": "Upload",
|
||||
"common.view": "View",
|
||||
"common.warning": "Warning",
|
||||
"common.yes": "Yes",
|
||||
"cookie.accept": "Got it",
|
||||
"cookie.notice": "DocuElevate uses only essential session cookies required for authentication and service operation. No tracking or analytics cookies are used.",
|
||||
"cookie.notice_label": "Cookie notice",
|
||||
"cookie.policy_link": "Cookie Policy",
|
||||
"cookie.privacy_link": "Privacy Notice",
|
||||
"dashboard.active_integrations": "Active Integrations",
|
||||
"dashboard.files_this_month": "Files This Month",
|
||||
"dashboard.files_today": "Files Today",
|
||||
"dashboard.ocr_processed": "OCR Processed",
|
||||
"dashboard.quick_actions": "Quick Actions",
|
||||
"dashboard.recent_activity": "Recent Activity",
|
||||
"dashboard.storage_targets": "Storage Targets",
|
||||
"dashboard.title": "Dashboard",
|
||||
"dashboard.total_files": "Total Files",
|
||||
"dashboard.welcome": "Welcome to DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "Forbidden",
|
||||
"error.forbidden_message": "You do not have permission to access this page.",
|
||||
"error.not_found": "Page not found",
|
||||
"error.not_found_message": "The page you are looking for does not exist.",
|
||||
"error.server_error": "Internal Server Error",
|
||||
"error.server_error_message": "Something went wrong. Please try again later.",
|
||||
"error.unauthorized": "Unauthorized",
|
||||
"error.unauthorized_message": "You need to log in to access this page.",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "Document Title",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "File Size",
|
||||
"files.filename": "Filename",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "No files found",
|
||||
"files.ocr_status": "OCR Status",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "Tags",
|
||||
"files.title": "Files",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "Uploaded",
|
||||
"footer.attributions": "Attributions",
|
||||
"footer.cookies": "Cookies",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "Imprint",
|
||||
"footer.license": "License",
|
||||
"footer.navigation": "Footer navigation",
|
||||
"footer.privacy": "Privacy",
|
||||
"footer.terms": "Terms",
|
||||
"footer.version": "Version {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "Documentation",
|
||||
"help.faq": "Frequently Asked Questions",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "Getting Started",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "Support",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "Help Center",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "Configure",
|
||||
"integrations.connect": "Connect",
|
||||
"integrations.connected": "Connected",
|
||||
"integrations.disconnect": "Disconnect",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "Not Connected",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "Integrations",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "Мову змінено на {language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "Українська",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "About",
|
||||
"nav.admin": "Admin",
|
||||
"nav.admin_actions": "Admin actions",
|
||||
"nav.admin_menu": "Admin menu",
|
||||
"nav.api_docs": "API Docs",
|
||||
"nav.backup_restore": "Backup & Restore",
|
||||
"nav.credentials": "Credentials",
|
||||
"nav.dark_mode": "Dark Mode",
|
||||
"nav.dashboard": "Dashboard",
|
||||
"nav.developer_docs": "Developer Docs",
|
||||
"nav.duplicates": "Duplicates",
|
||||
"nav.file_manager": "File Manager",
|
||||
"nav.files": "Files",
|
||||
"nav.help": "Help",
|
||||
"nav.help_center": "Help Center",
|
||||
"nav.integrations": "Integrations",
|
||||
"nav.light_mode": "Light Mode",
|
||||
"nav.main_navigation": "Main navigation",
|
||||
"nav.notifications": "Notifications",
|
||||
"nav.open_main_menu": "Open main menu",
|
||||
"nav.pipelines": "Pipelines",
|
||||
"nav.plan_designer": "Plan Designer",
|
||||
"nav.pricing": "Pricing",
|
||||
"nav.queue_monitor": "Queue Monitor",
|
||||
"nav.scheduled_jobs": "Scheduled Jobs",
|
||||
"nav.search": "Search",
|
||||
"nav.settings": "Settings",
|
||||
"nav.similarity": "Similarity",
|
||||
"nav.skip_to_content": "Skip to main content",
|
||||
"nav.status": "Status",
|
||||
"nav.toggle_dark_mode": "Toggle dark mode",
|
||||
"nav.toggle_nav": "Toggle navigation menu",
|
||||
"nav.upload": "Upload",
|
||||
"nav.users": "Users",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "Mark All as Read",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "Mark as Read",
|
||||
"notifications.no_notifications": "No notifications",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "Notifications",
|
||||
"notifications.unread_count": "{count} unread notifications",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "Create Pipeline",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "Edit Pipeline",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "Processing Pipelines",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "No results found",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "Search by filename, content, tags...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "{count} results found",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "Search Documents",
|
||||
"settings.reset_confirm": "Are you sure you want to reset this setting?",
|
||||
"settings.save_error": "Failed to save setting",
|
||||
"settings.save_success": "Setting saved successfully",
|
||||
"settings.title": "Settings",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "Drag & drop files here or click to browse",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "Upload failed",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "Maximum file size: {size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "Select File",
|
||||
"upload.success": "File uploaded successfully",
|
||||
"upload.title": "Upload Document",
|
||||
"upload.uploading": "Uploading...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"app.name": "DocuElevate",
|
||||
"auth.confirm_password": "Confirm Password",
|
||||
"auth.display_name_label": "Display Name",
|
||||
"auth.email_label": "Email",
|
||||
"auth.forgot_password": "Forgot Password?",
|
||||
"auth.login": "登录",
|
||||
"auth.login_title": "Log In",
|
||||
"auth.logout": "退出",
|
||||
"auth.my_account": "我的账户",
|
||||
"auth.password_label": "Password",
|
||||
"auth.profile": "个人资料",
|
||||
"auth.remember_me": "Remember me",
|
||||
"auth.signup": "注册",
|
||||
"auth.signup_title": "Sign Up",
|
||||
"auth.username_label": "Username",
|
||||
"common.actions": "操作",
|
||||
"common.active": "活跃",
|
||||
"common.all": "全部",
|
||||
"common.back": "返回",
|
||||
"common.cancel": "取消",
|
||||
"common.close": "关闭",
|
||||
"common.completed": "已完成",
|
||||
"common.confirm": "确认",
|
||||
"common.copied": "已复制!",
|
||||
"common.copy": "复制",
|
||||
"common.created": "创建时间",
|
||||
"common.date": "日期",
|
||||
"common.delete": "删除",
|
||||
"common.description": "描述",
|
||||
"common.details": "详情",
|
||||
"common.disabled": "已禁用",
|
||||
"common.download": "下载",
|
||||
"common.edit": "编辑",
|
||||
"common.enabled": "已启用",
|
||||
"common.error": "错误",
|
||||
"common.failed": "失败",
|
||||
"common.filter": "筛选",
|
||||
"common.inactive": "不活跃",
|
||||
"common.info": "信息",
|
||||
"common.loading": "加载中...",
|
||||
"common.name": "名称",
|
||||
"common.next": "下一步",
|
||||
"common.no": "否",
|
||||
"common.none": "无",
|
||||
"common.pending": "待处理",
|
||||
"common.processing": "处理中",
|
||||
"common.refresh": "刷新",
|
||||
"common.reset": "重置",
|
||||
"common.retry": "重试",
|
||||
"common.save": "保存",
|
||||
"common.search": "搜索",
|
||||
"common.select": "选择",
|
||||
"common.size": "大小",
|
||||
"common.status": "状态",
|
||||
"common.success": "成功",
|
||||
"common.type": "类型",
|
||||
"common.updated": "更新时间",
|
||||
"common.upload": "上传",
|
||||
"common.view": "查看",
|
||||
"common.warning": "警告",
|
||||
"common.yes": "是",
|
||||
"cookie.accept": "我知道了",
|
||||
"cookie.notice": "DocuElevate 仅使用身份验证和服务运行所需的基本会话 Cookie。不使用任何跟踪或分析 Cookie。",
|
||||
"cookie.notice_label": "Cookie 通知",
|
||||
"cookie.policy_link": "Cookie 政策",
|
||||
"cookie.privacy_link": "隐私声明",
|
||||
"dashboard.active_integrations": "活跃集成",
|
||||
"dashboard.files_this_month": "本月文件",
|
||||
"dashboard.files_today": "今日文件",
|
||||
"dashboard.ocr_processed": "OCR 已处理",
|
||||
"dashboard.quick_actions": "快捷操作",
|
||||
"dashboard.recent_activity": "最近活动",
|
||||
"dashboard.storage_targets": "存储目标",
|
||||
"dashboard.title": "仪表盘",
|
||||
"dashboard.total_files": "文件总数",
|
||||
"dashboard.welcome": "欢迎使用 DocuElevate",
|
||||
"error.404_code": "404",
|
||||
"error.404_heading": "Oops, we couldn’t find that page!",
|
||||
"error.404_home": "Return Home",
|
||||
"error.404_message": "It seems DocuElevate has misplaced the document you were looking for. Don’t worry – we’ve got your back.",
|
||||
"error.500_code": "500",
|
||||
"error.500_description": "Our servers encountered a mishap and need a moment.",
|
||||
"error.500_heading": "Oops! Something Went Wrong.",
|
||||
"error.500_home": "Go Home",
|
||||
"error.forbidden": "禁止访问",
|
||||
"error.forbidden_message": "您没有权限访问此页面。",
|
||||
"error.not_found": "页面未找到",
|
||||
"error.not_found_message": "您要查找的页面不存在。",
|
||||
"error.server_error": "服务器内部错误",
|
||||
"error.server_error_message": "出了点问题,请稍后再试。",
|
||||
"error.unauthorized": "未授权",
|
||||
"error.unauthorized_message": "您需要登录才能访问此页面。",
|
||||
"files.action_delete": "Delete file",
|
||||
"files.action_details": "View details",
|
||||
"files.action_preview": "Quick preview",
|
||||
"files.bulk_clear_selection": "Clear Selection",
|
||||
"files.bulk_cloud_ocr": "Re-run Cloud OCR",
|
||||
"files.bulk_delete": "Delete Selected",
|
||||
"files.bulk_download": "Download as ZIP",
|
||||
"files.bulk_reprocess": "Reprocess Selected",
|
||||
"files.delete_modal_cancel": "Cancel",
|
||||
"files.delete_modal_confirm": "Delete",
|
||||
"files.delete_modal_message": "Are you sure you want to delete this file?",
|
||||
"files.delete_modal_title": "Confirm Deletion",
|
||||
"files.document_title": "文档标题",
|
||||
"files.drop_overlay_hint": "Supports PDF, Office docs, images, HTML, Markdown, and more",
|
||||
"files.drop_overlay_title": "Drop files or folders anywhere to upload",
|
||||
"files.file_size": "文件大小",
|
||||
"files.filename": "文件名",
|
||||
"files.filter_all_providers": "All Providers",
|
||||
"files.filter_all_statuses": "All Statuses",
|
||||
"files.filter_all_types": "All Types",
|
||||
"files.filter_apply": "Apply Filters",
|
||||
"files.filter_clear": "Clear",
|
||||
"files.filter_date_from": "Date From",
|
||||
"files.filter_date_to": "Date To",
|
||||
"files.filter_mime_type": "MIME Type",
|
||||
"files.filter_ocr_all": "All Files",
|
||||
"files.filter_ocr_good": "Good quality",
|
||||
"files.filter_ocr_poor": "Poor quality",
|
||||
"files.filter_ocr_quality": "OCR Quality",
|
||||
"files.filter_ocr_unchecked": "Not yet assessed",
|
||||
"files.filter_search_placeholder": "Enter filename...",
|
||||
"files.filter_storage_provider": "Storage Provider",
|
||||
"files.filter_tags_placeholder": "e.g. invoice,amazon",
|
||||
"files.fulltext_search_label": "Full-Text Search",
|
||||
"files.fulltext_search_placeholder": "Search document content, sender, tags, type...",
|
||||
"files.no_files": "未找到文件",
|
||||
"files.ocr_status": "OCR 状态",
|
||||
"files.page_title": "File Records",
|
||||
"files.pagination_first": "First",
|
||||
"files.pagination_last": "Last",
|
||||
"files.pagination_next": "Next",
|
||||
"files.pagination_previous": "Previous",
|
||||
"files.preview_modal_close": "Close preview",
|
||||
"files.preview_modal_title": "Preview",
|
||||
"files.queue_banner_link": "View Queue",
|
||||
"files.saved_searches_empty": "No saved searches yet",
|
||||
"files.saved_searches_error": "Could not load saved searches",
|
||||
"files.saved_searches_label": "Saved Searches",
|
||||
"files.saved_searches_save": "Save Current",
|
||||
"files.search_results_empty": "No results found.",
|
||||
"files.search_results_title": "Search Results",
|
||||
"files.table_actions": "Actions",
|
||||
"files.table_created_at": "Created At",
|
||||
"files.table_empty": "No files found",
|
||||
"files.table_id": "ID",
|
||||
"files.table_mime_type": "MIME Type",
|
||||
"files.table_original_filename": "Original Filename",
|
||||
"files.table_select_all": "Select all files on this page",
|
||||
"files.tags": "标签",
|
||||
"files.title": "文件",
|
||||
"files.upload_modal_header": "Uploading Files",
|
||||
"files.uploaded": "已上传",
|
||||
"footer.attributions": "致谢",
|
||||
"footer.cookies": "Cookie",
|
||||
"footer.copyright": "DocuElevate {year}",
|
||||
"footer.imprint": "法律声明",
|
||||
"footer.license": "许可",
|
||||
"footer.navigation": "页脚导航",
|
||||
"footer.privacy": "隐私",
|
||||
"footer.terms": "条款",
|
||||
"footer.version": "版本 {version}",
|
||||
"help.destinations_dropbox": "Dropbox",
|
||||
"help.destinations_dropbox_desc": "OAuth-linked. Files land in your chosen folder.",
|
||||
"help.destinations_email": "Email Forwarding",
|
||||
"help.destinations_email_desc": "Processed files sent as SMTP attachments.",
|
||||
"help.destinations_google_drive": "Google Drive",
|
||||
"help.destinations_google_drive_desc": "Service account or OAuth. Supports shared drives.",
|
||||
"help.destinations_heading": "Destinations – Where Documents Go",
|
||||
"help.destinations_nextcloud": "Nextcloud / WebDAV",
|
||||
"help.destinations_nextcloud_desc": "Self-hosted cloud storage via WebDAV.",
|
||||
"help.destinations_onedrive": "OneDrive",
|
||||
"help.destinations_onedrive_desc": "Microsoft Graph API integration.",
|
||||
"help.destinations_paperless": "Paperless-ngx",
|
||||
"help.destinations_paperless_desc": "Push documents straight into Paperless for archival.",
|
||||
"help.destinations_s3": "Amazon S3",
|
||||
"help.destinations_s3_desc": "Any S3-compatible bucket (AWS, MinIO, Wasabi).",
|
||||
"help.destinations_sftp": "SFTP / FTP",
|
||||
"help.destinations_sftp_desc": "Secure file transfer to any server.",
|
||||
"help.destinations_webhook": "Webhook",
|
||||
"help.destinations_webhook_desc": "POST metadata to any external endpoint.",
|
||||
"help.documentation": "文档",
|
||||
"help.faq": "常见问题",
|
||||
"help.faq_1_a": "Navigate to the Upload page, drag-and-drop your files or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.faq_1_q": "How do I upload documents?",
|
||||
"help.faq_2_a": "PDF, JPEG, PNG, TIFF, BMP, GIF, DOCX, XLSX, PPTX, ODT, ODS, TXT, RTF, and HTML. Non-PDF files are automatically converted to PDF before processing.",
|
||||
"help.faq_2_q": "Which file formats are supported?",
|
||||
"help.faq_3_a": "Yes. Go to Email Ingestion, add an IMAP account, and DocuElevate will poll for new messages and process attachments automatically.",
|
||||
"help.faq_3_q": "Can I ingest documents from email?",
|
||||
"help.faq_4_a": "Pipelines let you chain processing steps – OCR, AI extraction, format conversion – and route the result to one or more destinations. Create and manage them from the Pipelines page.",
|
||||
"help.faq_4_q": "How do processing pipelines work?",
|
||||
"help.faq_5_a": "DocuElevate encrypts credentials at rest, communicates over TLS, and never stores your documents longer than necessary. See the Privacy Notice for full details.",
|
||||
"help.faq_5_q": "Is my data secure?",
|
||||
"help.faq_heading": "Frequently Asked Questions",
|
||||
"help.getting_started": "入门指南",
|
||||
"help.heading": "Help Center",
|
||||
"help.page_title": "Help Center",
|
||||
"help.quickstart_heading": "Quick Start",
|
||||
"help.quickstart_storage": "Connect Storage",
|
||||
"help.quickstart_storage_desc": "Head to Settings and link your cloud accounts. Processed documents are automatically routed to every destination you configure.",
|
||||
"help.quickstart_upload": "Upload Documents",
|
||||
"help.quickstart_upload_desc": "Drag & drop files onto the Upload page or click Choose File. DocuElevate converts images and office documents to PDF, runs OCR, and extracts metadata automatically.",
|
||||
"help.quickstart_workflows": "Automate Workflows",
|
||||
"help.quickstart_workflows_desc": "Create Pipelines to define multi-step processing and routing rules. Combine OCR, AI extraction, format conversion, and delivery in a single flow.",
|
||||
"help.sources_email_ingestion": "Email Ingestion (IMAP)",
|
||||
"help.sources_email_ingestion_desc": "Forward documents to a dedicated mailbox. Under Email Ingestion, add one or more IMAP accounts. DocuElevate polls for new messages and processes attachments automatically.",
|
||||
"help.sources_heading": "Sources – Getting Documents In",
|
||||
"help.sources_rest_api": "REST API",
|
||||
"help.sources_rest_api_desc": "Integrate programmatically by POST-ing files to /api/upload. Ideal for scripts, watched folders, scanners, or third-party tools like Zapier and n8n.",
|
||||
"help.sources_scanner": "Scanner & Mobile",
|
||||
"help.sources_scanner_desc": "Point network scanners at DocuElevate's upload endpoint or use any mobile scanning app that supports custom HTTP destinations.",
|
||||
"help.sources_web_upload": "Web Upload",
|
||||
"help.sources_web_upload_desc": "The fastest way to get started. Open the Upload page, drop one or more files, and DocuElevate takes care of the rest. Supported formats include PDF, JPEG, PNG, TIFF, DOCX, XLSX, and more.",
|
||||
"help.subheading": "Everything you need to get the most out of DocuElevate. Browse topics below or search for what you need.",
|
||||
"help.support": "支持",
|
||||
"help.support_admin_message": "Contact your administrator for support information.",
|
||||
"help.support_description": "Can’t find what you’re looking for? Our support team is here to help.",
|
||||
"help.support_heading": "Contact Support",
|
||||
"help.title": "帮助中心",
|
||||
"help.workflows_creating": "Creating a Pipeline",
|
||||
"help.workflows_definition": "A Pipeline is a series of processing steps that run automatically whenever a document is ingested. Each step can transform, enrich, or route the document.",
|
||||
"help.workflows_heading": "Workflows & Pipelines",
|
||||
"help.workflows_step_1": "Convert to PDF",
|
||||
"help.workflows_step_1_create": "Go to Pipelines in the main menu.",
|
||||
"help.workflows_step_2": "OCR – extract text",
|
||||
"help.workflows_step_2_create": "Click New Pipeline and give it a name.",
|
||||
"help.workflows_step_3": "AI metadata extraction",
|
||||
"help.workflows_step_3_create": "Add the processing steps you need.",
|
||||
"help.workflows_step_4": "Deliver to one or more destinations",
|
||||
"help.workflows_step_4_create": "Choose one or more delivery destinations.",
|
||||
"help.workflows_step_5_create": "Save – new documents will be processed through this pipeline automatically.",
|
||||
"help.workflows_typical_steps": "Typical Steps",
|
||||
"help.workflows_what_is": "What is a Pipeline?",
|
||||
"index.badge_intelligent": "Intelligent Document Processing",
|
||||
"index.capabilities_cloud": "Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud",
|
||||
"index.capabilities_ingestion": "Email & URL-based document ingestion",
|
||||
"index.capabilities_ocr": "OCR & metadata extraction with AI",
|
||||
"index.capabilities_paperless": "Paperless-ngx integration for document management",
|
||||
"index.capabilities_title": "Capabilities",
|
||||
"index.capabilities_workflows": "Automated classification & routing workflows",
|
||||
"index.cta_description": "Join teams already automating their document processing with DocuElevate.",
|
||||
"index.cta_heading": "Ready to elevate your document workflow?",
|
||||
"index.cta_pricing": "See pricing",
|
||||
"index.cta_signup": "Create a free account",
|
||||
"index.dashboard_subtitle": "Intelligent document processing & management",
|
||||
"index.feature_ai": "AI Metadata Extraction",
|
||||
"index.feature_ai_desc": "OpenAI, Claude, Gemini, and other pluggable AI providers classify documents and pull out key fields like dates, amounts, and subjects.",
|
||||
"index.feature_cloud": "Multi-Cloud Storage",
|
||||
"index.feature_cloud_desc": "Route processed files to Dropbox, Google Drive, OneDrive, Amazon S3, Nextcloud, Paperless NGX, WebDAV, FTP/SFTP, and more.",
|
||||
"index.feature_email": "Email & IMAP Ingestion",
|
||||
"index.feature_email_desc": "Automatically pull documents from Gmail or any IMAP mailbox — no manual uploads needed.",
|
||||
"index.feature_ocr": "OCR & Text Extraction",
|
||||
"index.feature_ocr_desc": "Azure Document Intelligence converts scanned PDFs and images into fully searchable text automatically.",
|
||||
"index.feature_pipelines": "Custom Pipelines",
|
||||
"index.feature_pipelines_desc": "Build processing pipelines with configurable steps — OCR, AI extraction, format conversion, and storage routing in any order.",
|
||||
"index.feature_search": "Full-Text Search",
|
||||
"index.feature_search_desc": "Instantly find any document by content, metadata, or tags across your entire archive.",
|
||||
"index.feature_section_title": "Everything you need for smart document workflows",
|
||||
"index.getting_started": "Getting Started",
|
||||
"index.getting_started_1": "Configure integrations via System Status",
|
||||
"index.getting_started_2": "Upload your first document",
|
||||
"index.getting_started_3": "Review results in Files",
|
||||
"index.getting_started_learn": "Learn more about DocuElevate",
|
||||
"index.hero_description": "DocuElevate ingests your documents, runs OCR, extracts metadata with AI, and routes files to Dropbox, Google Drive, OneDrive, S3, Nextcloud, and more — all in one seamless pipeline.",
|
||||
"index.hero_heading": "From upload to insight — automatically.",
|
||||
"index.hero_login": "Log In",
|
||||
"index.hero_pricing": "View Plans & Pricing",
|
||||
"index.hero_signup": "Get Started — it’s free",
|
||||
"index.integrations_active": "Active integrations",
|
||||
"index.integrations_storage": "Storage targets",
|
||||
"index.integrations_title": "Integrations",
|
||||
"index.integrations_view_status": "View system status",
|
||||
"index.page_title_dashboard": "Dashboard",
|
||||
"index.page_title_public": "Intelligent Document Processing",
|
||||
"index.platform_overview": "Platform overview",
|
||||
"index.quick_actions": "Quick Actions",
|
||||
"index.quick_documents": "My Documents",
|
||||
"index.quick_documents_desc": "Browse your processed files",
|
||||
"index.quick_search": "Search",
|
||||
"index.quick_search_desc": "Full-text search across documents",
|
||||
"index.quick_subscription": "My Subscription",
|
||||
"index.quick_subscription_desc": "View plan & usage details",
|
||||
"index.quick_upload": "Upload Document",
|
||||
"index.quick_upload_desc": "Process a new file",
|
||||
"index.single_user_heading": "DocuElevate Dashboard",
|
||||
"index.single_user_subtitle": "Intelligent document processing & management",
|
||||
"index.stat_active_users": "Active users",
|
||||
"index.stat_files_month": "Files this month",
|
||||
"index.stat_files_today": "Files today",
|
||||
"index.stat_total_files": "Total files",
|
||||
"index.tier_plan": "Plan",
|
||||
"index.tier_upgrade": "Upgrade",
|
||||
"index.tier_view_details": "View full details",
|
||||
"index.upgrade_daily_limits": "Higher daily & monthly limits",
|
||||
"index.upgrade_description": "Unlock more documents, more destinations and priority support.",
|
||||
"index.upgrade_destinations": "More storage destinations",
|
||||
"index.upgrade_ocr_pages": "More OCR pages",
|
||||
"index.upgrade_plan": "Upgrade your plan",
|
||||
"index.upgrade_view_pricing": "View plans & pricing",
|
||||
"index.usage_lifetime": "Lifetime files",
|
||||
"index.usage_month": "Files this month",
|
||||
"index.usage_my_usage": "My usage",
|
||||
"index.usage_today": "Files today",
|
||||
"index.usage_unlimited": "Unlimited",
|
||||
"integrations.configure": "配置",
|
||||
"integrations.connect": "连接",
|
||||
"integrations.connected": "已连接",
|
||||
"integrations.disconnect": "断开",
|
||||
"integrations.empty_state": "No integrations configured",
|
||||
"integrations.folder_label": "Folder",
|
||||
"integrations.host_label": "Host",
|
||||
"integrations.imap_settings": "IMAP Settings",
|
||||
"integrations.not_connected": "未连接",
|
||||
"integrations.page_title": "Integrations",
|
||||
"integrations.password_label": "Password",
|
||||
"integrations.port_label": "Port",
|
||||
"integrations.title": "集成",
|
||||
"integrations.username_label": "Username",
|
||||
"language.bg": "Български",
|
||||
"language.ca": "Català",
|
||||
"language.changed": "语言已更改为{language}",
|
||||
"language.cs": "Čeština",
|
||||
"language.da": "Dansk",
|
||||
"language.de": "Deutsch",
|
||||
"language.el": "Ελληνικά",
|
||||
"language.en": "English",
|
||||
"language.es": "Español",
|
||||
"language.et": "Eesti",
|
||||
"language.fi": "Suomi",
|
||||
"language.fr": "Français",
|
||||
"language.ga": "Gaeilge",
|
||||
"language.hr": "Hrvatski",
|
||||
"language.hu": "Magyar",
|
||||
"language.is": "Íslenska",
|
||||
"language.it": "Italiano",
|
||||
"language.lb": "Lëtzebuergesch",
|
||||
"language.lt": "Lietuvių",
|
||||
"language.lv": "Latviešu",
|
||||
"language.nb": "Norsk",
|
||||
"language.nl": "Nederlands",
|
||||
"language.pl": "Polski",
|
||||
"language.pt": "Português",
|
||||
"language.ro": "Română",
|
||||
"language.ru": "Русский",
|
||||
"language.selector": "语言",
|
||||
"language.sk": "Slovenčina",
|
||||
"language.sl": "Slovenščina",
|
||||
"language.sv": "Svenska",
|
||||
"language.tr": "Türkçe",
|
||||
"language.uk": "Українська",
|
||||
"language.zh": "中文",
|
||||
"nav.about": "关于",
|
||||
"nav.admin": "管理",
|
||||
"nav.admin_actions": "管理操作",
|
||||
"nav.admin_menu": "管理菜单",
|
||||
"nav.api_docs": "API 文档",
|
||||
"nav.backup_restore": "备份与恢复",
|
||||
"nav.credentials": "凭据",
|
||||
"nav.dark_mode": "深色模式",
|
||||
"nav.dashboard": "仪表盘",
|
||||
"nav.developer_docs": "开发者文档",
|
||||
"nav.duplicates": "重复文件",
|
||||
"nav.file_manager": "文件管理器",
|
||||
"nav.files": "文件",
|
||||
"nav.help": "帮助",
|
||||
"nav.help_center": "帮助中心",
|
||||
"nav.integrations": "集成",
|
||||
"nav.light_mode": "浅色模式",
|
||||
"nav.main_navigation": "主导航",
|
||||
"nav.notifications": "通知",
|
||||
"nav.open_main_menu": "打开主菜单",
|
||||
"nav.pipelines": "处理流程",
|
||||
"nav.plan_designer": "方案设计",
|
||||
"nav.pricing": "价格",
|
||||
"nav.queue_monitor": "队列监控",
|
||||
"nav.scheduled_jobs": "计划任务",
|
||||
"nav.search": "搜索",
|
||||
"nav.settings": "设置",
|
||||
"nav.similarity": "相似度",
|
||||
"nav.skip_to_content": "跳至主要内容",
|
||||
"nav.status": "状态",
|
||||
"nav.toggle_dark_mode": "切换深色模式",
|
||||
"nav.toggle_nav": "切换导航菜单",
|
||||
"nav.upload": "上传",
|
||||
"nav.users": "用户",
|
||||
"notifications.filter_all": "All",
|
||||
"notifications.filter_read": "Read only",
|
||||
"notifications.filter_unread": "Unread only",
|
||||
"notifications.manage_desc": "Manage your notification inbox, targets, and event preferences",
|
||||
"notifications.mark_all_read": "全部标记为已读",
|
||||
"notifications.mark_all_read_btn": "Mark all read",
|
||||
"notifications.mark_read": "标记为已读",
|
||||
"notifications.no_notifications": "没有通知",
|
||||
"notifications.page_title": "Notifications",
|
||||
"notifications.tab_inbox": "Inbox",
|
||||
"notifications.tab_settings": "Settings",
|
||||
"notifications.title": "通知",
|
||||
"notifications.unread_count": "{count} 条未读通知",
|
||||
"pipelines.active_label": "Active",
|
||||
"pipelines.create": "创建流程",
|
||||
"pipelines.default_label": "Default",
|
||||
"pipelines.description_label": "Description",
|
||||
"pipelines.disabled_label": "Disabled",
|
||||
"pipelines.edit": "编辑流程",
|
||||
"pipelines.empty_state": "No pipelines yet",
|
||||
"pipelines.enabled_label": "Enabled",
|
||||
"pipelines.inactive_label": "Inactive",
|
||||
"pipelines.page_title": "Processing Pipelines",
|
||||
"pipelines.set_default": "Set as my default pipeline",
|
||||
"pipelines.system_label": "System",
|
||||
"pipelines.title": "处理流程",
|
||||
"search.button": "Search",
|
||||
"search.error_message": "Search is temporarily unavailable. Please try again in a moment.",
|
||||
"search.filter_clear_button": "Clear Filters",
|
||||
"search.filter_date_from": "Date From",
|
||||
"search.filter_date_to": "Date To",
|
||||
"search.filter_document_type": "Document Type",
|
||||
"search.filter_document_type_placeholder": "e.g. Invoice",
|
||||
"search.filter_language": "Language",
|
||||
"search.filter_language_placeholder": "e.g. de",
|
||||
"search.filter_sender": "Sender",
|
||||
"search.filter_sender_placeholder": "e.g. ACME Corp",
|
||||
"search.filter_tags_placeholder": "e.g. amazon",
|
||||
"search.filter_text_quality": "Text Quality",
|
||||
"search.filter_text_quality_all": "All",
|
||||
"search.filter_text_quality_high": "High",
|
||||
"search.filter_text_quality_low": "Low",
|
||||
"search.filter_text_quality_medium": "Medium",
|
||||
"search.filter_text_quality_no_text": "No text",
|
||||
"search.heading": "Document Search",
|
||||
"search.input_placeholder": "Search documents by content, sender, tags, type...",
|
||||
"search.loading_indicator": "Searching…",
|
||||
"search.no_results": "未找到结果",
|
||||
"search.page_title": "Search Documents",
|
||||
"search.placeholder": "按文件名、内容、标签搜索...",
|
||||
"search.result_empty": "No documents found matching your query.",
|
||||
"search.results_count": "找到 {count} 个结果",
|
||||
"search.saved_button": "Save Current",
|
||||
"search.saved_empty": "No saved searches yet",
|
||||
"search.saved_error": "Could not load saved searches",
|
||||
"search.saved_label": "Saved Searches",
|
||||
"search.saved_loading": "Loading...",
|
||||
"search.title": "搜索文档",
|
||||
"settings.reset_confirm": "确定要重置此设置吗?",
|
||||
"settings.save_error": "设置保存失败",
|
||||
"settings.save_success": "设置保存成功",
|
||||
"settings.title": "设置",
|
||||
"status.app_version": "App Version",
|
||||
"status.build_date": "Build Date",
|
||||
"status.container_id": "Container ID",
|
||||
"status.git_commit": "Git Commit",
|
||||
"status.last_check": "Last Check",
|
||||
"status.page_title": "System Status",
|
||||
"status.setting_label": "Setting",
|
||||
"status.value_label": "Value",
|
||||
"upload.browse_button": "Browse Files",
|
||||
"upload.button_processing": "Processing...",
|
||||
"upload.camera_button": "Take Photo / Scan Document",
|
||||
"upload.download_button": "Download and Process",
|
||||
"upload.downloading": "Downloading file from URL...",
|
||||
"upload.drag_drop": "将文件拖放到此处或点击浏览",
|
||||
"upload.drop_hint_desktop": "Drag & drop files or folders here, or click to select files.",
|
||||
"upload.drop_hint_mobile": "Tap to select files or use the camera button below.",
|
||||
"upload.error": "上传失败",
|
||||
"upload.error_invalid_url": "Invalid URL format",
|
||||
"upload.error_url_required": "Please enter a URL",
|
||||
"upload.file_size_hint": "Maximum size: 500 MB per file",
|
||||
"upload.file_types": "Allowed types: PDF, Office documents (Word, Excel, PowerPoint, etc.), Images",
|
||||
"upload.filename_description": "Leave empty to use filename from URL",
|
||||
"upload.filename_label": "Filename (optional)",
|
||||
"upload.filename_placeholder": "my-document.pdf",
|
||||
"upload.max_size": "最大文件大小:{size}",
|
||||
"upload.page_title": "Upload Files",
|
||||
"upload.section_device": "Upload from Device",
|
||||
"upload.section_url": "Upload from URL",
|
||||
"upload.select_file": "选择文件",
|
||||
"upload.success": "文件上传成功",
|
||||
"upload.title": "上传文档",
|
||||
"upload.uploading": "上传中...",
|
||||
"upload.url_description": "Enter a direct link to a file (PDF, Office documents, or images)",
|
||||
"upload.url_label": "File URL",
|
||||
"upload.url_placeholder": "https://example.com/document.pdf"
|
||||
}
|
||||
@@ -20,13 +20,31 @@ from app.database import Base
|
||||
|
||||
# Ensure all models are imported so Base.metadata is populated.
|
||||
from app.models import ( # noqa: F401
|
||||
ApiToken,
|
||||
ApplicationSettings,
|
||||
AuditLog,
|
||||
BackupRecord,
|
||||
ComplianceTemplate,
|
||||
DocumentMetadata,
|
||||
FileProcessingStep,
|
||||
FileRecord,
|
||||
InAppNotification,
|
||||
LocalUser,
|
||||
MobileDevice,
|
||||
Pipeline,
|
||||
PipelineStep,
|
||||
ProcessingLog,
|
||||
SavedSearch,
|
||||
ScheduledJob,
|
||||
SettingsAuditLog,
|
||||
SharedLink,
|
||||
SubscriptionPlan,
|
||||
UserImapAccount,
|
||||
UserIntegration,
|
||||
UserNotificationPreference,
|
||||
UserNotificationTarget,
|
||||
UserProfile,
|
||||
WebhookConfig,
|
||||
)
|
||||
|
||||
# Alembic Config object – provides access to values in alembic.ini.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
"""Ensure shared_links table exists for databases that skipped migration 025.
|
||||
|
||||
Databases that were already at revision 025_add_user_notifications or
|
||||
026_add_scheduled_jobs before 025_add_shared_links was inserted into the
|
||||
migration chain will never have had the ``shared_links`` table created.
|
||||
This migration creates the table idempotently so those databases are
|
||||
repaired on the next ``alembic upgrade head``.
|
||||
|
||||
Revision ID: 027_ensure_shared_links_table
|
||||
Revises: 026_add_scheduled_jobs
|
||||
Create Date: 2026-03-09
|
||||
"""
|
||||
|
||||
from typing import Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "027_ensure_shared_links_table"
|
||||
down_revision: Union[str, None] = "026_add_scheduled_jobs"
|
||||
depends_on: Union[str, None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Create shared_links table if it does not already exist."""
|
||||
conn = op.get_bind()
|
||||
inspector = sa.inspect(conn)
|
||||
if "shared_links" not in inspector.get_table_names():
|
||||
op.create_table(
|
||||
"shared_links",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("token", sa.String(64), nullable=False),
|
||||
sa.Column("file_id", sa.Integer(), nullable=False),
|
||||
sa.Column("owner_id", sa.String(), nullable=False),
|
||||
sa.Column("label", sa.String(255), nullable=True),
|
||||
sa.Column("expires_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("max_views", sa.Integer(), nullable=True),
|
||||
sa.Column("view_count", sa.Integer(), nullable=False, server_default="0"),
|
||||
sa.Column("password_hash", sa.String(128), nullable=True),
|
||||
sa.Column("is_active", sa.Boolean(), nullable=False, server_default="1"),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.ForeignKeyConstraint(["file_id"], ["files.id"]),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("token"),
|
||||
)
|
||||
op.create_index("ix_shared_links_id", "shared_links", ["id"])
|
||||
op.create_index("ix_shared_links_token", "shared_links", ["token"])
|
||||
op.create_index("ix_shared_links_file_id", "shared_links", ["file_id"])
|
||||
op.create_index("ix_shared_links_owner_id", "shared_links", ["owner_id"])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Drop shared_links table only if this migration created it."""
|
||||
conn = op.get_bind()
|
||||
inspector = sa.inspect(conn)
|
||||
if "shared_links" in inspector.get_table_names():
|
||||
op.drop_index("ix_shared_links_owner_id", "shared_links")
|
||||
op.drop_index("ix_shared_links_file_id", "shared_links")
|
||||
op.drop_index("ix_shared_links_token", "shared_links")
|
||||
op.drop_index("ix_shared_links_id", "shared_links")
|
||||
op.drop_table("shared_links")
|
||||
@@ -0,0 +1,47 @@
|
||||
"""Add audit_logs table for comprehensive compliance audit logging.
|
||||
|
||||
Revision ID: 028_add_audit_logs
|
||||
Revises: 027_ensure_shared_links_table
|
||||
Create Date: 2026-03-09
|
||||
"""
|
||||
|
||||
from typing import Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "028_add_audit_logs"
|
||||
down_revision: Union[str, None] = "027_ensure_shared_links_table"
|
||||
depends_on: Union[str, None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Create audit_logs table."""
|
||||
op.create_table(
|
||||
"audit_logs",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("timestamp", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
|
||||
sa.Column("user", sa.String(), nullable=False),
|
||||
sa.Column("action", sa.String(), nullable=False),
|
||||
sa.Column("resource_type", sa.String(), nullable=True),
|
||||
sa.Column("resource_id", sa.String(), nullable=True),
|
||||
sa.Column("ip_address", sa.String(), nullable=True),
|
||||
sa.Column("details", sa.Text(), nullable=True),
|
||||
sa.Column("severity", sa.String(16), nullable=False, server_default="info"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_index("ix_audit_logs_id", "audit_logs", ["id"])
|
||||
op.create_index("ix_audit_logs_timestamp", "audit_logs", ["timestamp"])
|
||||
op.create_index("ix_audit_logs_user", "audit_logs", ["user"])
|
||||
op.create_index("ix_audit_logs_action", "audit_logs", ["action"])
|
||||
op.create_index("ix_audit_logs_resource_type", "audit_logs", ["resource_type"])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Drop audit_logs table."""
|
||||
op.drop_index("ix_audit_logs_resource_type", "audit_logs")
|
||||
op.drop_index("ix_audit_logs_action", "audit_logs")
|
||||
op.drop_index("ix_audit_logs_user", "audit_logs")
|
||||
op.drop_index("ix_audit_logs_timestamp", "audit_logs")
|
||||
op.drop_index("ix_audit_logs_id", "audit_logs")
|
||||
op.drop_table("audit_logs")
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Add preferred_language column to user_profiles for i18n support.
|
||||
|
||||
Revision ID: 029_add_user_language_preference
|
||||
Revises: 028_add_audit_logs
|
||||
Create Date: 2026-03-09
|
||||
"""
|
||||
|
||||
from typing import Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "029_add_user_language_preference"
|
||||
down_revision: Union[str, None] = "028_add_audit_logs"
|
||||
depends_on: Union[str, None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Add preferred_language column to user_profiles table."""
|
||||
conn = op.get_bind()
|
||||
inspector = sa.inspect(conn)
|
||||
if "user_profiles" not in inspector.get_table_names():
|
||||
return
|
||||
existing_columns = {col["name"] for col in inspector.get_columns("user_profiles")}
|
||||
if "preferred_language" not in existing_columns:
|
||||
op.add_column(
|
||||
"user_profiles",
|
||||
sa.Column("preferred_language", sa.String(10), nullable=True, server_default=None),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Remove preferred_language column from user_profiles table."""
|
||||
conn = op.get_bind()
|
||||
inspector = sa.inspect(conn)
|
||||
if "user_profiles" not in inspector.get_table_names():
|
||||
return
|
||||
existing_columns = {col["name"] for col in inspector.get_columns("user_profiles")}
|
||||
if "preferred_language" in existing_columns:
|
||||
op.drop_column("user_profiles", "preferred_language")
|
||||
@@ -0,0 +1,41 @@
|
||||
"""Add mobile_devices table for push notification device registration.
|
||||
|
||||
Revision ID: 030_add_mobile_devices
|
||||
Revises: 029_add_user_language_preference
|
||||
Create Date: 2026-03-10
|
||||
"""
|
||||
|
||||
from typing import Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "030_add_mobile_devices"
|
||||
down_revision: Union[str, None] = "029_add_user_language_preference"
|
||||
depends_on: Union[str, None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Create mobile_devices table."""
|
||||
op.create_table(
|
||||
"mobile_devices",
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("owner_id", sa.String(), nullable=False),
|
||||
sa.Column("device_name", sa.String(255), nullable=True),
|
||||
sa.Column("platform", sa.String(20), nullable=False, server_default="ios"),
|
||||
sa.Column("push_token", sa.String(512), nullable=False),
|
||||
sa.Column("is_active", sa.Boolean(), nullable=False, server_default="1"),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()),
|
||||
sa.Column("last_seen_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint("owner_id", "push_token", name="uq_mobile_device_owner_token"),
|
||||
)
|
||||
op.create_index("ix_mobile_devices_id", "mobile_devices", ["id"])
|
||||
op.create_index("ix_mobile_devices_owner_id", "mobile_devices", ["owner_id"])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Drop mobile_devices table."""
|
||||
op.drop_index("ix_mobile_devices_owner_id", table_name="mobile_devices")
|
||||
op.drop_index("ix_mobile_devices_id", table_name="mobile_devices")
|
||||
op.drop_table("mobile_devices")
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
"""Add compliance_templates table for GDPR, HIPAA, SOC2 compliance templates.
|
||||
|
||||
Revision ID: 027_add_compliance_templates
|
||||
Revises: 026_add_scheduled_jobs
|
||||
Revision ID: 031_add_compliance_templates
|
||||
Revises: 030_add_mobile_devices
|
||||
Create Date: 2026-03-09
|
||||
"""
|
||||
|
||||
@@ -10,8 +10,8 @@ from typing import Union
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "027_add_compliance_templates"
|
||||
down_revision: Union[str, None] = "026_add_scheduled_jobs"
|
||||
revision: str = "031_add_compliance_templates"
|
||||
down_revision: Union[str, None] = "030_add_mobile_devices"
|
||||
depends_on: Union[str, None] = None
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
node_modules/
|
||||
.expo/
|
||||
dist/
|
||||
web-build/
|
||||
ios/
|
||||
android/
|
||||
.env
|
||||
google-services.json
|
||||
GoogleService-Info.plist
|
||||
*.jks
|
||||
*.p8
|
||||
*.p12
|
||||
*.key
|
||||
*.mobileprovision
|
||||
*.orig.*
|
||||
npm-debug.*
|
||||
yarn-debug.*
|
||||
yarn-error.*
|
||||
.idea/
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* App.tsx – root component for the DocuElevate mobile app.
|
||||
*
|
||||
* Wraps the entire app in the AuthProvider and renders either the login
|
||||
* screen (unauthenticated) or the main tab navigator (authenticated).
|
||||
* Push notification registration is handled by the usePushNotifications hook.
|
||||
*/
|
||||
|
||||
import { NavigationContainer } from "@react-navigation/native";
|
||||
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
|
||||
import React from "react";
|
||||
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
|
||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||
import { AuthProvider, useAuth } from "./src/context/AuthContext";
|
||||
import { usePushNotifications } from "./src/hooks/usePushNotifications";
|
||||
import FilesScreen from "./src/screens/FilesScreen";
|
||||
import LoginScreen from "./src/screens/LoginScreen";
|
||||
import ProfileScreen from "./src/screens/ProfileScreen";
|
||||
import UploadScreen from "./src/screens/UploadScreen";
|
||||
|
||||
const Tab = createBottomTabNavigator();
|
||||
|
||||
function TabNavigator() {
|
||||
const { isAuthenticated } = useAuth();
|
||||
usePushNotifications(isAuthenticated);
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: "#1e40af",
|
||||
tabBarInactiveTintColor: "#9ca3af",
|
||||
tabBarStyle: {
|
||||
borderTopColor: "#e5e7eb",
|
||||
backgroundColor: "#ffffff",
|
||||
},
|
||||
headerStyle: {
|
||||
backgroundColor: "#1e40af",
|
||||
},
|
||||
headerTintColor: "#ffffff",
|
||||
headerTitleStyle: {
|
||||
fontWeight: "700",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Tab.Screen
|
||||
name="Upload"
|
||||
component={UploadScreen}
|
||||
options={{
|
||||
title: "Upload",
|
||||
tabBarLabel: "Upload",
|
||||
tabBarIcon: ({ color }) => (
|
||||
<Text style={{ fontSize: 20, color }}>⬆️</Text>
|
||||
),
|
||||
headerTitle: "DocuElevate",
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Files"
|
||||
component={FilesScreen}
|
||||
options={{
|
||||
title: "Files",
|
||||
tabBarLabel: "Files",
|
||||
tabBarIcon: ({ color }) => (
|
||||
<Text style={{ fontSize: 20, color }}>📄</Text>
|
||||
),
|
||||
headerTitle: "My Documents",
|
||||
}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name="Profile"
|
||||
component={ProfileScreen}
|
||||
options={{
|
||||
title: "Profile",
|
||||
tabBarLabel: "Profile",
|
||||
tabBarIcon: ({ color }) => (
|
||||
<Text style={{ fontSize: 20, color }}>👤</Text>
|
||||
),
|
||||
headerTitle: "Profile",
|
||||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
function AppContent() {
|
||||
const { isLoading, isAuthenticated } = useAuth();
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<View style={styles.loading}>
|
||||
<ActivityIndicator size="large" color="#1e40af" />
|
||||
<Text style={styles.loadingText}>Loading…</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationContainer>
|
||||
{isAuthenticated ? <TabNavigator /> : <LoginScreen />}
|
||||
</NavigationContainer>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<SafeAreaProvider>
|
||||
<AuthProvider>
|
||||
<AppContent />
|
||||
</AuthProvider>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
loading: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#f9fafb",
|
||||
gap: 12,
|
||||
},
|
||||
loadingText: {
|
||||
color: "#6b7280",
|
||||
fontSize: 15,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,142 @@
|
||||
# DocuElevate Mobile App
|
||||
|
||||
Native mobile application for DocuElevate, built with **React Native** and **Expo** for both iOS (primary) and Android.
|
||||
|
||||
## Features
|
||||
|
||||
- 🔐 **SSO Login** – authenticate via your DocuElevate server's OAuth2/SSO provider; an API token is auto-generated and stored securely in the device keychain
|
||||
- 📷 **Camera Capture** – scan documents directly with the device camera
|
||||
- 📄 **File Picker** – upload PDFs, images, and Office documents from the device's Files app
|
||||
- 🔗 **Share Extension** – send files from any app directly to DocuElevate via the iOS/Android share sheet
|
||||
- 🔔 **Push Notifications** – receive real-time push notifications when documents finish processing (via Expo push notifications)
|
||||
- 📂 **Document List** – browse and search your processed documents
|
||||
- 👤 **Profile** – view account details and sign out
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18+
|
||||
- Expo CLI (`npm install -g @expo/cli`)
|
||||
- Expo Go app on device (for development) **or** Expo Application Services (EAS) for production builds
|
||||
- An Expo account: <https://expo.dev/>
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
# 1. Install dependencies
|
||||
cd mobile
|
||||
npm install
|
||||
|
||||
# 2. Start the development server
|
||||
npx expo start
|
||||
```
|
||||
|
||||
Scan the QR code with **Expo Go** on your iOS or Android device.
|
||||
|
||||
## Building
|
||||
|
||||
DocuElevate uses **EAS Build** for production binaries.
|
||||
|
||||
```bash
|
||||
# Install EAS CLI
|
||||
npm install -g eas-cli
|
||||
|
||||
# Log in to Expo
|
||||
eas login
|
||||
|
||||
# Configure your project (one-time) – updates app.json with the EAS project ID
|
||||
eas init
|
||||
|
||||
# Build for iOS
|
||||
eas build --platform ios
|
||||
|
||||
# Build for Android
|
||||
eas build --platform android
|
||||
|
||||
# Build for both
|
||||
eas build --platform all
|
||||
```
|
||||
|
||||
> **After running `eas init`:** update the `extra.eas.projectId` field in `app.json` with the value printed by the command.
|
||||
|
||||
### iOS-specific
|
||||
|
||||
- An Apple Developer account is required for TestFlight and App Store distribution
|
||||
- Update `eas.json` → `submit.production.ios` with:
|
||||
- `appleId`: your Apple ID email address
|
||||
- `ascAppId`: App Store Connect → App Information → Apple ID
|
||||
- `appleTeamId`: Apple Developer portal → Membership → Team ID
|
||||
- Camera, photo library, and push notification usage descriptions are configured in `app.json`
|
||||
|
||||
### Android-specific
|
||||
|
||||
- Add a `google-services.json` file (from Firebase Console) to the `mobile/` directory for push notification support
|
||||
- For Play Store submission: create a service account in Google Play Console, download the JSON key as `google-play-service-account.json`, and update `eas.json`
|
||||
|
||||
## Configuration
|
||||
|
||||
No code changes are needed to point the app at a different server. The server URL is entered by the user on the login screen and stored in the device's secure store.
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
1. User enters the DocuElevate server URL on the login screen
|
||||
2. The app opens the server's `/login?mobile=1&redirect_uri=docuelevate://callback` URL in the system browser
|
||||
3. The user authenticates (SSO / local login)
|
||||
4. The server redirects back to `docuelevate://callback`
|
||||
5. The app exchanges the browser session for a permanent API token via `POST /api/mobile/generate-token`
|
||||
6. The token is stored in the device's secure keychain (`expo-secure-store`)
|
||||
|
||||
## Push Notifications
|
||||
|
||||
The app uses **Expo Push Notifications** which route through Expo's servers to APNs (iOS) and FCM (Android) – no server-side APNs/FCM credentials are needed.
|
||||
|
||||
The Expo push token is sent to the backend after login via `POST /api/mobile/register-device` and the server uses it to deliver notifications when documents are processed.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
mobile/
|
||||
├── App.tsx # Root component
|
||||
├── app.json # Expo configuration
|
||||
├── eas.json # EAS Build configuration
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── src/
|
||||
├── context/
|
||||
│ └── AuthContext.tsx # Authentication state management
|
||||
├── hooks/
|
||||
│ └── usePushNotifications.ts # Push notification registration
|
||||
├── screens/
|
||||
│ ├── LoginScreen.tsx # SSO login
|
||||
│ ├── UploadScreen.tsx # Camera capture + file picker
|
||||
│ ├── FilesScreen.tsx # Document list
|
||||
│ └── ProfileScreen.tsx # User profile + sign out
|
||||
└── services/
|
||||
└── api.ts # DocuElevate API client
|
||||
```
|
||||
|
||||
## Share Extension (iOS)
|
||||
|
||||
The app registers the `docuelevate://` URL scheme and the `com.docuelevate.app` bundle identifier. To enable the share sheet:
|
||||
|
||||
1. Ensure the app is installed on the device
|
||||
2. Open any file in Files, Mail, Safari, etc.
|
||||
3. Tap the share icon → find **DocuElevate** in the share sheet
|
||||
4. The file is uploaded immediately
|
||||
|
||||
Android uses a similar intent filter configured in `app.json`.
|
||||
|
||||
## Backend API
|
||||
|
||||
The mobile app uses the following backend endpoints:
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|----------|-------------------------------------|---------------------------------------|
|
||||
| `POST` | `/api/mobile/generate-token` | Exchange SSO session for API token |
|
||||
| `POST` | `/api/mobile/register-device` | Register Expo push token |
|
||||
| `GET` | `/api/mobile/devices` | List registered devices |
|
||||
| `DELETE` | `/api/mobile/devices/{id}` | Deactivate device registration |
|
||||
| `GET` | `/api/mobile/whoami` | Get current user profile |
|
||||
| `POST` | `/api/ui-upload` | Upload file for processing |
|
||||
| `GET` | `/api/files` | List processed documents |
|
||||
|
||||
Authentication uses `Authorization: Bearer <api_token>` on all requests.
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "DocuElevate",
|
||||
"slug": "docuelevate",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "automatic",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#1e40af"
|
||||
},
|
||||
"assetBundlePatterns": ["**/*"],
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "com.docuelevate.app",
|
||||
"infoPlist": {
|
||||
"NSCameraUsageDescription": "DocuElevate uses the camera to capture documents for upload.",
|
||||
"NSPhotoLibraryUsageDescription": "DocuElevate accesses your photo library to select documents for upload.",
|
||||
"NSPhotoLibraryAddUsageDescription": "DocuElevate saves scanned documents to your photo library.",
|
||||
"UIBackgroundModes": ["fetch", "remote-notification"]
|
||||
},
|
||||
"buildNumber": "1"
|
||||
},
|
||||
"android": {
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#1e40af"
|
||||
},
|
||||
"package": "com.docuelevate.app",
|
||||
"permissions": [
|
||||
"CAMERA",
|
||||
"READ_EXTERNAL_STORAGE",
|
||||
"WRITE_EXTERNAL_STORAGE",
|
||||
"RECEIVE_BOOT_COMPLETED",
|
||||
"VIBRATE"
|
||||
],
|
||||
"versionCode": 1,
|
||||
"googleServicesFile": "./google-services.json"
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
},
|
||||
"plugins": [
|
||||
"expo-router",
|
||||
[
|
||||
"expo-notifications",
|
||||
{
|
||||
"icon": "./assets/notification-icon.png",
|
||||
"color": "#1e40af",
|
||||
"sounds": ["./assets/notification-sound.wav"]
|
||||
}
|
||||
],
|
||||
[
|
||||
"expo-camera",
|
||||
{
|
||||
"cameraPermission": "DocuElevate uses the camera to capture documents for upload."
|
||||
}
|
||||
],
|
||||
"expo-document-picker",
|
||||
"expo-secure-store",
|
||||
"expo-sharing"
|
||||
],
|
||||
"scheme": "docuelevate",
|
||||
"extra": {
|
||||
"eas": {
|
||||
"projectId": "YOUR_EAS_PROJECT_ID"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = function (api) {
|
||||
api.cache(true);
|
||||
return {
|
||||
presets: ["babel-preset-expo"],
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"cli": {
|
||||
"version": ">= 5.9.0"
|
||||
},
|
||||
"build": {
|
||||
"development": {
|
||||
"developmentClient": true,
|
||||
"distribution": "internal"
|
||||
},
|
||||
"preview": {
|
||||
"distribution": "internal",
|
||||
"ios": {
|
||||
"simulator": false
|
||||
}
|
||||
},
|
||||
"production": {
|
||||
"autoIncrement": true
|
||||
}
|
||||
},
|
||||
"submit": {
|
||||
"production": {
|
||||
"ios": {
|
||||
"appleId": "YOUR_APPLE_ID",
|
||||
"ascAppId": "YOUR_APP_STORE_CONNECT_APP_ID",
|
||||
"appleTeamId": "YOUR_APPLE_TEAM_ID"
|
||||
},
|
||||
"android": {
|
||||
"serviceAccountKeyPath": "./google-play-service-account.json",
|
||||
"track": "production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "docuelevate-mobile",
|
||||
"version": "1.0.0",
|
||||
"description": "DocuElevate native mobile app (iOS and Android)",
|
||||
"main": "expo-router/entry",
|
||||
"scripts": {
|
||||
"start": "expo start",
|
||||
"android": "expo start --android",
|
||||
"ios": "expo start --ios",
|
||||
"web": "expo start --web",
|
||||
"lint": "eslint src --ext .ts,.tsx",
|
||||
"type-check": "tsc --noEmit",
|
||||
"build:ios": "eas build --platform ios",
|
||||
"build:android": "eas build --platform android",
|
||||
"build:all": "eas build --platform all",
|
||||
"submit:ios": "eas submit --platform ios",
|
||||
"submit:android": "eas submit --platform android"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/vector-icons": "^14.0.0",
|
||||
"@react-native-async-storage/async-storage": "1.23.1",
|
||||
"@react-navigation/bottom-tabs": "^6.6.1",
|
||||
"@react-navigation/native": "^6.1.18",
|
||||
"@react-navigation/native-stack": "^6.11.0",
|
||||
"expo": "~51.0.0",
|
||||
"expo-auth-session": "~5.5.2",
|
||||
"expo-camera": "~15.0.16",
|
||||
"expo-constants": "~16.0.2",
|
||||
"expo-crypto": "~13.0.2",
|
||||
"expo-document-picker": "~12.0.2",
|
||||
"expo-file-system": "~17.0.1",
|
||||
"expo-image-manipulator": "~12.0.5",
|
||||
"expo-image-picker": "~15.0.7",
|
||||
"expo-linking": "~6.3.1",
|
||||
"expo-notifications": "~0.28.15",
|
||||
"expo-router": "~3.5.23",
|
||||
"expo-secure-store": "~13.0.2",
|
||||
"expo-sharing": "~12.0.1",
|
||||
"expo-splash-screen": "~0.27.5",
|
||||
"expo-status-bar": "~1.12.1",
|
||||
"expo-web-browser": "~13.0.3",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.74.5",
|
||||
"react-native-safe-area-context": "4.10.5",
|
||||
"react-native-screens": "3.31.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.0",
|
||||
"@types/react": "~18.2.79",
|
||||
"@types/react-native": "^0.73.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-expo": "~7.0.0",
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
"private": true,
|
||||
"expo": {
|
||||
"doctor": {
|
||||
"reactNativeDirectoryCheck": {
|
||||
"exclude": ["@react-navigation/bottom-tabs"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Authentication context for the DocuElevate mobile app.
|
||||
*
|
||||
* Manages the lifecycle of the stored API token and user profile. The SSO
|
||||
* login flow uses expo-auth-session to open the server's OAuth page in the
|
||||
* system browser; on return the redirect URL carries a one-time code that is
|
||||
* exchanged for a session cookie, which is then traded for a permanent API
|
||||
* token via POST /api/mobile/generate-token.
|
||||
*/
|
||||
|
||||
import * as SecureStore from "expo-secure-store";
|
||||
import * as WebBrowser from "expo-web-browser";
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
SECURE_STORE_API_TOKEN_KEY,
|
||||
SECURE_STORE_BASE_URL_KEY,
|
||||
SECURE_STORE_OWNER_ID_KEY,
|
||||
api,
|
||||
type WhoAmIResponse,
|
||||
} from "../services/api";
|
||||
|
||||
WebBrowser.maybeCompleteAuthSession();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface AuthState {
|
||||
isLoading: boolean;
|
||||
isAuthenticated: boolean;
|
||||
user: WhoAmIResponse | null;
|
||||
baseUrl: string;
|
||||
signIn: (serverUrl: string) => Promise<void>;
|
||||
signOut: () => Promise<void>;
|
||||
setToken: (token: string) => Promise<void>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Context
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const AuthContext = createContext<AuthState>({
|
||||
isLoading: true,
|
||||
isAuthenticated: false,
|
||||
user: null,
|
||||
baseUrl: "",
|
||||
signIn: async () => {},
|
||||
signOut: async () => {},
|
||||
setToken: async () => {},
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Provider
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [user, setUser] = useState<WhoAmIResponse | null>(null);
|
||||
const [baseUrl, setBaseUrl] = useState("");
|
||||
|
||||
// On mount: restore persisted session
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const storedUrl = await SecureStore.getItemAsync(SECURE_STORE_BASE_URL_KEY);
|
||||
const storedToken = await SecureStore.getItemAsync(SECURE_STORE_API_TOKEN_KEY);
|
||||
|
||||
if (storedUrl && storedToken) {
|
||||
await api.init(storedUrl);
|
||||
setBaseUrl(storedUrl);
|
||||
// Verify token is still valid
|
||||
const profile = await api.whoAmI();
|
||||
setUser(profile);
|
||||
setIsAuthenticated(true);
|
||||
}
|
||||
} catch {
|
||||
// Token expired or server unavailable – clear stored credentials
|
||||
await SecureStore.deleteItemAsync(SECURE_STORE_API_TOKEN_KEY);
|
||||
await SecureStore.deleteItemAsync(SECURE_STORE_OWNER_ID_KEY);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const setToken = useCallback(async (token: string) => {
|
||||
await SecureStore.setItemAsync(SECURE_STORE_API_TOKEN_KEY, token);
|
||||
const profile = await api.whoAmI();
|
||||
setUser(profile);
|
||||
await SecureStore.setItemAsync(SECURE_STORE_OWNER_ID_KEY, profile.owner_id);
|
||||
setIsAuthenticated(true);
|
||||
}, []);
|
||||
|
||||
const signIn = useCallback(
|
||||
async (serverUrl: string) => {
|
||||
const cleanUrl = serverUrl.replace(/\/$/, "");
|
||||
await api.init(cleanUrl);
|
||||
setBaseUrl(cleanUrl);
|
||||
|
||||
// Open the web login page in the system browser. The user authenticates
|
||||
// via SSO or local credentials, then the app deep-link (docuelevate://callback)
|
||||
// is triggered. The WebBrowser.openAuthSessionAsync handles the redirect
|
||||
// back to the app.
|
||||
const result = await WebBrowser.openAuthSessionAsync(
|
||||
`${cleanUrl}/login?mobile=1&redirect_uri=docuelevate://callback`,
|
||||
"docuelevate://callback"
|
||||
);
|
||||
|
||||
if (result.type !== "success") {
|
||||
throw new Error("Authentication was cancelled or failed");
|
||||
}
|
||||
|
||||
// Parse the token from the redirect URL if the server appended it,
|
||||
// otherwise hit the generate-token endpoint (session cookie is carried
|
||||
// by the WebBrowser).
|
||||
const url = new URL(result.url);
|
||||
const inlineToken = url.searchParams.get("token");
|
||||
|
||||
if (inlineToken) {
|
||||
await setToken(inlineToken);
|
||||
} else {
|
||||
// The server set a session cookie during the browser session; exchange
|
||||
// it for a persistent API token.
|
||||
const deviceInfo = await _getDeviceName();
|
||||
const tokenResp = await api.generateMobileToken(deviceInfo);
|
||||
await setToken(tokenResp.token);
|
||||
}
|
||||
},
|
||||
[setToken]
|
||||
);
|
||||
|
||||
const signOut = useCallback(async () => {
|
||||
await SecureStore.deleteItemAsync(SECURE_STORE_API_TOKEN_KEY);
|
||||
await SecureStore.deleteItemAsync(SECURE_STORE_OWNER_ID_KEY);
|
||||
setUser(null);
|
||||
setIsAuthenticated(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{
|
||||
isLoading,
|
||||
isAuthenticated,
|
||||
user,
|
||||
baseUrl,
|
||||
signIn,
|
||||
signOut,
|
||||
setToken,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Hook
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function useAuth(): AuthState {
|
||||
return useContext(AuthContext);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function _getDeviceName(): Promise<string> {
|
||||
try {
|
||||
const Constants = await import("expo-constants");
|
||||
return (
|
||||
Constants.default.deviceName ||
|
||||
Constants.default.expoConfig?.name ||
|
||||
"Mobile App"
|
||||
);
|
||||
} catch {
|
||||
return "Mobile App";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* usePushNotifications – register the device for push notifications.
|
||||
*
|
||||
* Requests the user's permission for notifications, obtains an Expo push
|
||||
* token, and registers it with the DocuElevate backend via
|
||||
* POST /api/mobile/register-device.
|
||||
*
|
||||
* This hook should be called once from the root component after the user has
|
||||
* successfully authenticated.
|
||||
*/
|
||||
|
||||
import Constants from "expo-constants";
|
||||
import * as Device from "expo-device";
|
||||
import * as Notifications from "expo-notifications";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import { Platform } from "react-native";
|
||||
import api from "../services/api";
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: true,
|
||||
}),
|
||||
});
|
||||
|
||||
export function usePushNotifications(isAuthenticated: boolean) {
|
||||
const notificationListener = useRef<Notifications.Subscription | null>(null);
|
||||
const responseListener = useRef<Notifications.Subscription | null>(null);
|
||||
|
||||
const registerForPushNotifications = useCallback(async () => {
|
||||
if (!Device.isDevice) {
|
||||
// Push tokens are not available in simulators.
|
||||
return;
|
||||
}
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
await Notifications.setNotificationChannelAsync("default", {
|
||||
name: "DocuElevate",
|
||||
importance: Notifications.AndroidImportance.MAX,
|
||||
vibrationPattern: [0, 250, 250, 250],
|
||||
lightColor: "#1e40af",
|
||||
});
|
||||
}
|
||||
|
||||
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
||||
let finalStatus = existingStatus;
|
||||
|
||||
if (existingStatus !== "granted") {
|
||||
const { status } = await Notifications.requestPermissionsAsync();
|
||||
finalStatus = status;
|
||||
}
|
||||
|
||||
if (finalStatus !== "granted") {
|
||||
// User declined – no push notifications
|
||||
return;
|
||||
}
|
||||
|
||||
let projectId: string | undefined;
|
||||
try {
|
||||
projectId =
|
||||
Constants.expoConfig?.extra?.eas?.projectId ??
|
||||
Constants.easConfig?.projectId;
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const tokenData = await Notifications.getExpoPushTokenAsync(
|
||||
projectId ? { projectId } : undefined
|
||||
);
|
||||
|
||||
const pushToken = tokenData.data;
|
||||
const platform = Platform.OS as "ios" | "android" | "web";
|
||||
|
||||
let deviceName = "Mobile App";
|
||||
try {
|
||||
deviceName = Device.modelName ?? Device.deviceName ?? "Mobile App";
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
await api.registerDevice({ push_token: pushToken, device_name: deviceName, platform });
|
||||
} catch {
|
||||
// Registration failure is non-fatal – the app still works without push.
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) return;
|
||||
|
||||
registerForPushNotifications();
|
||||
|
||||
// Listen for incoming notifications while app is foregrounded
|
||||
notificationListener.current = Notifications.addNotificationReceivedListener((notification) => {
|
||||
console.log("Notification received:", notification.request.content.title);
|
||||
});
|
||||
|
||||
// Listen for user taps on notifications
|
||||
responseListener.current = Notifications.addNotificationResponseReceivedListener((response) => {
|
||||
const data = response.notification.request.content.data as Record<string, unknown>;
|
||||
// Navigate to file detail if file_id is present
|
||||
if (data?.file_id) {
|
||||
console.log("User tapped notification for file:", data.file_id);
|
||||
// Navigation would be wired up by the caller via a callback prop
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
notificationListener.current?.remove();
|
||||
responseListener.current?.remove();
|
||||
};
|
||||
}, [isAuthenticated, registerForPushNotifications]);
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* FilesScreen – list of documents processed by DocuElevate.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList,
|
||||
Pressable,
|
||||
RefreshControl,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from "react-native";
|
||||
import type { FileRecord } from "../services/api";
|
||||
import api from "../services/api";
|
||||
|
||||
function formatBytes(bytes: number | null): string {
|
||||
if (bytes === null || bytes === undefined) return "–";
|
||||
if (bytes < 1024) return `${bytes} B`;
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
||||
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
||||
}
|
||||
|
||||
function formatDate(iso: string): string {
|
||||
try {
|
||||
return new Date(iso).toLocaleDateString(undefined, {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
} catch {
|
||||
return iso;
|
||||
}
|
||||
}
|
||||
|
||||
function statusEmoji(status: string): string {
|
||||
const map: Record<string, string> = {
|
||||
processed: "✅",
|
||||
processing: "⚙️",
|
||||
queued: "⏳",
|
||||
failed: "❌",
|
||||
uploaded: "⬆️",
|
||||
};
|
||||
return map[status?.toLowerCase()] ?? "📄";
|
||||
}
|
||||
|
||||
export default function FilesScreen() {
|
||||
const [files, setFiles] = useState<FileRecord[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [page, setPage] = useState(1);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchFiles = useCallback(
|
||||
async (pageNum: number, replace: boolean) => {
|
||||
try {
|
||||
const data = await api.listFiles(pageNum, 20);
|
||||
if (replace) {
|
||||
setFiles(data);
|
||||
} else {
|
||||
setFiles((prev) => [...prev, ...data]);
|
||||
}
|
||||
setHasMore(data.length === 20);
|
||||
setError(null);
|
||||
} catch (err: unknown) {
|
||||
setError(err instanceof Error ? err.message : "Failed to load files");
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setLoading(true);
|
||||
await fetchFiles(1, true);
|
||||
setLoading(false);
|
||||
})();
|
||||
}, [fetchFiles]);
|
||||
|
||||
const handleRefresh = useCallback(async () => {
|
||||
setRefreshing(true);
|
||||
setPage(1);
|
||||
await fetchFiles(1, true);
|
||||
setRefreshing(false);
|
||||
}, [fetchFiles]);
|
||||
|
||||
const handleLoadMore = useCallback(async () => {
|
||||
if (!hasMore || loading || refreshing) return;
|
||||
const next = page + 1;
|
||||
setPage(next);
|
||||
await fetchFiles(next, false);
|
||||
}, [fetchFiles, hasMore, loading, page, refreshing]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View style={styles.center}>
|
||||
<ActivityIndicator size="large" color="#1e40af" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<View style={styles.center}>
|
||||
<Text style={styles.errorText}>{error}</Text>
|
||||
<Pressable style={styles.retryButton} onPress={handleRefresh}>
|
||||
<Text style={styles.retryText}>Retry</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
style={styles.list}
|
||||
data={files}
|
||||
keyExtractor={(item) => String(item.id)}
|
||||
contentContainerStyle={styles.listContent}
|
||||
renderItem={({ item }) => <FileRow file={item} />}
|
||||
refreshControl={
|
||||
<RefreshControl refreshing={refreshing} onRefresh={handleRefresh} />
|
||||
}
|
||||
onEndReached={handleLoadMore}
|
||||
onEndReachedThreshold={0.4}
|
||||
ListEmptyComponent={
|
||||
<View style={styles.emptyState}>
|
||||
<Text style={styles.emptyEmoji}>📂</Text>
|
||||
<Text style={styles.emptyText}>No documents yet.</Text>
|
||||
<Text style={styles.emptyHint}>
|
||||
Upload a document from the Upload tab to get started.
|
||||
</Text>
|
||||
</View>
|
||||
}
|
||||
ListFooterComponent={
|
||||
hasMore && files.length > 0 ? (
|
||||
<ActivityIndicator color="#1e40af" style={{ marginVertical: 16 }} />
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function FileRow({ file }: { file: FileRecord }) {
|
||||
return (
|
||||
<View style={rowStyles.row}>
|
||||
<Text style={rowStyles.icon}>{statusEmoji(file.status)}</Text>
|
||||
<View style={rowStyles.info}>
|
||||
<Text style={rowStyles.filename} numberOfLines={1}>
|
||||
{file.filename}
|
||||
</Text>
|
||||
<Text style={rowStyles.meta}>
|
||||
{formatDate(file.created_at)} · {formatBytes(file.file_size)}
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={rowStyles.status}>{file.status}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
list: { flex: 1, backgroundColor: "#f9fafb" },
|
||||
listContent: { padding: 16 },
|
||||
center: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#f9fafb",
|
||||
padding: 24,
|
||||
},
|
||||
errorText: { color: "#dc2626", fontSize: 15, textAlign: "center", marginBottom: 16 },
|
||||
retryButton: {
|
||||
backgroundColor: "#1e40af",
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 24,
|
||||
paddingVertical: 10,
|
||||
},
|
||||
retryText: { color: "#fff", fontWeight: "600" },
|
||||
emptyState: { alignItems: "center", paddingTop: 60 },
|
||||
emptyEmoji: { fontSize: 48, marginBottom: 12 },
|
||||
emptyText: { fontSize: 16, color: "#374151", marginBottom: 8 },
|
||||
emptyHint: {
|
||||
fontSize: 13,
|
||||
color: "#6b7280",
|
||||
textAlign: "center",
|
||||
paddingHorizontal: 32,
|
||||
},
|
||||
});
|
||||
|
||||
const rowStyles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 10,
|
||||
padding: 14,
|
||||
marginBottom: 10,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.04,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 4,
|
||||
elevation: 2,
|
||||
},
|
||||
icon: { fontSize: 22, marginRight: 12 },
|
||||
info: { flex: 1 },
|
||||
filename: {
|
||||
fontSize: 14,
|
||||
fontWeight: "600",
|
||||
color: "#111827",
|
||||
marginBottom: 4,
|
||||
},
|
||||
meta: { fontSize: 12, color: "#6b7280" },
|
||||
status: {
|
||||
fontSize: 11,
|
||||
color: "#6b7280",
|
||||
fontWeight: "500",
|
||||
textTransform: "capitalize",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* LoginScreen – entry point for unauthenticated users.
|
||||
*
|
||||
* Renders a server URL input and a "Sign in with SSO" button that opens the
|
||||
* DocuElevate web login page in the system browser. On success the
|
||||
* AuthContext stores the API token and navigates to the main app.
|
||||
*/
|
||||
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
Pressable,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
|
||||
export default function LoginScreen() {
|
||||
const { signIn } = useAuth();
|
||||
const [serverUrl, setServerUrl] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
async function handleSignIn() {
|
||||
const url = serverUrl.trim();
|
||||
if (!url) {
|
||||
Alert.alert("Server URL required", "Please enter the URL of your DocuElevate server.");
|
||||
return;
|
||||
}
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
Alert.alert("Invalid URL", "The server URL must start with http:// or https://");
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
await signIn(url);
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Sign-in failed";
|
||||
Alert.alert("Sign-in failed", message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.container}
|
||||
behavior={Platform.OS === "ios" ? "padding" : undefined}
|
||||
>
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.logo}>DocuElevate</Text>
|
||||
<Text style={styles.tagline}>Intelligent Document Processing</Text>
|
||||
|
||||
<Text style={styles.label}>Server URL</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="https://your-docuelevate-server.com"
|
||||
placeholderTextColor="#9ca3af"
|
||||
value={serverUrl}
|
||||
onChangeText={setServerUrl}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
keyboardType="url"
|
||||
returnKeyType="go"
|
||||
onSubmitEditing={handleSignIn}
|
||||
accessibilityLabel="Server URL"
|
||||
/>
|
||||
|
||||
<Pressable
|
||||
style={[styles.button, loading && styles.buttonDisabled]}
|
||||
onPress={handleSignIn}
|
||||
disabled={loading}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Sign in with SSO"
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color="#fff" />
|
||||
) : (
|
||||
<Text style={styles.buttonText}>Sign in with SSO</Text>
|
||||
)}
|
||||
</Pressable>
|
||||
|
||||
<Text style={styles.hint}>
|
||||
You will be redirected to your organisation's sign-in page.
|
||||
</Text>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f3f4f6",
|
||||
justifyContent: "center",
|
||||
padding: 24,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: "#ffffff",
|
||||
borderRadius: 16,
|
||||
padding: 28,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.08,
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowRadius: 12,
|
||||
elevation: 4,
|
||||
},
|
||||
logo: {
|
||||
fontSize: 28,
|
||||
fontWeight: "700",
|
||||
color: "#1e40af",
|
||||
textAlign: "center",
|
||||
marginBottom: 4,
|
||||
},
|
||||
tagline: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
textAlign: "center",
|
||||
marginBottom: 32,
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: "600",
|
||||
color: "#374151",
|
||||
marginBottom: 6,
|
||||
},
|
||||
input: {
|
||||
borderWidth: 1,
|
||||
borderColor: "#d1d5db",
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
fontSize: 15,
|
||||
color: "#111827",
|
||||
marginBottom: 20,
|
||||
backgroundColor: "#f9fafb",
|
||||
},
|
||||
button: {
|
||||
backgroundColor: "#1e40af",
|
||||
borderRadius: 8,
|
||||
paddingVertical: 14,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 48,
|
||||
},
|
||||
buttonDisabled: {
|
||||
opacity: 0.6,
|
||||
},
|
||||
buttonText: {
|
||||
color: "#ffffff",
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
},
|
||||
hint: {
|
||||
marginTop: 16,
|
||||
fontSize: 12,
|
||||
color: "#9ca3af",
|
||||
textAlign: "center",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* ProfileScreen – authenticated user profile and settings.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
Alert,
|
||||
Image,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Switch,
|
||||
Text,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
|
||||
export default function ProfileScreen() {
|
||||
const { user, signOut, baseUrl } = useAuth();
|
||||
|
||||
function handleSignOut() {
|
||||
Alert.alert("Sign out", "Are you sure you want to sign out?", [
|
||||
{ text: "Cancel", style: "cancel" },
|
||||
{
|
||||
text: "Sign out",
|
||||
style: "destructive",
|
||||
onPress: signOut,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return (
|
||||
<View style={styles.center}>
|
||||
<Text style={styles.emptyText}>Not signed in</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.scroll} contentContainerStyle={styles.content}>
|
||||
{/* Avatar + name */}
|
||||
<View style={styles.profileCard}>
|
||||
{user.avatar_url ? (
|
||||
<Image
|
||||
source={{ uri: user.avatar_url }}
|
||||
style={styles.avatar}
|
||||
accessibilityLabel={`Avatar for ${user.display_name ?? user.owner_id}`}
|
||||
/>
|
||||
) : (
|
||||
<View style={[styles.avatar, styles.avatarPlaceholder]}>
|
||||
<Text style={styles.avatarInitial}>
|
||||
{(user.display_name ?? user.owner_id).charAt(0).toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text style={styles.displayName}>{user.display_name ?? user.owner_id}</Text>
|
||||
{user.email && <Text style={styles.email}>{user.email}</Text>}
|
||||
{user.is_admin && <Text style={styles.adminBadge}>Admin</Text>}
|
||||
</View>
|
||||
|
||||
{/* Server info */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Connection</Text>
|
||||
<View style={styles.row}>
|
||||
<Text style={styles.rowLabel}>Server</Text>
|
||||
<Text style={styles.rowValue} numberOfLines={1}>
|
||||
{baseUrl || "–"}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.row}>
|
||||
<Text style={styles.rowLabel}>User ID</Text>
|
||||
<Text style={styles.rowValue} numberOfLines={1}>
|
||||
{user.owner_id}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Danger zone */}
|
||||
<View style={styles.section}>
|
||||
<Pressable
|
||||
style={styles.signOutButton}
|
||||
onPress={handleSignOut}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Sign out"
|
||||
>
|
||||
<Text style={styles.signOutText}>Sign out</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
scroll: { flex: 1, backgroundColor: "#f9fafb" },
|
||||
content: { padding: 20 },
|
||||
center: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "#f9fafb",
|
||||
},
|
||||
emptyText: { color: "#6b7280", fontSize: 16 },
|
||||
profileCard: {
|
||||
alignItems: "center",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 16,
|
||||
padding: 24,
|
||||
marginBottom: 20,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.06,
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowRadius: 12,
|
||||
elevation: 3,
|
||||
},
|
||||
avatar: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 40,
|
||||
marginBottom: 14,
|
||||
},
|
||||
avatarPlaceholder: {
|
||||
backgroundColor: "#1e40af",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
avatarInitial: {
|
||||
color: "#fff",
|
||||
fontSize: 32,
|
||||
fontWeight: "700",
|
||||
},
|
||||
displayName: {
|
||||
fontSize: 20,
|
||||
fontWeight: "700",
|
||||
color: "#111827",
|
||||
marginBottom: 4,
|
||||
},
|
||||
email: { fontSize: 14, color: "#6b7280", marginBottom: 6 },
|
||||
adminBadge: {
|
||||
backgroundColor: "#dbeafe",
|
||||
color: "#1e40af",
|
||||
fontSize: 11,
|
||||
fontWeight: "700",
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 3,
|
||||
borderRadius: 12,
|
||||
overflow: "hidden",
|
||||
},
|
||||
section: {
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
marginBottom: 16,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.04,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 6,
|
||||
elevation: 2,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 13,
|
||||
fontWeight: "700",
|
||||
color: "#6b7280",
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 0.5,
|
||||
marginBottom: 12,
|
||||
},
|
||||
row: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingVertical: 8,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#f3f4f6",
|
||||
},
|
||||
rowLabel: { fontSize: 14, color: "#374151" },
|
||||
rowValue: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
maxWidth: "60%",
|
||||
textAlign: "right",
|
||||
},
|
||||
signOutButton: {
|
||||
backgroundColor: "#fee2e2",
|
||||
borderRadius: 10,
|
||||
paddingVertical: 14,
|
||||
alignItems: "center",
|
||||
minHeight: 48,
|
||||
},
|
||||
signOutText: {
|
||||
color: "#dc2626",
|
||||
fontWeight: "700",
|
||||
fontSize: 15,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* UploadScreen – document upload via camera or file picker.
|
||||
*
|
||||
* Users can:
|
||||
* 1. Take a photo of a document with the device camera.
|
||||
* 2. Pick an existing file (PDF, image, Office document) from the Files app.
|
||||
* 3. Receive files shared from other apps via the iOS Share Sheet / Android
|
||||
* Share Intent (handled by the expo-sharing + deep-link integration).
|
||||
*/
|
||||
|
||||
import * as DocumentPicker from "expo-document-picker";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import api from "../services/api";
|
||||
|
||||
interface UploadItem {
|
||||
id: string;
|
||||
filename: string;
|
||||
status: "pending" | "uploading" | "done" | "error";
|
||||
error?: string;
|
||||
taskId?: string;
|
||||
}
|
||||
|
||||
export default function UploadScreen() {
|
||||
const { isAuthenticated } = useAuth();
|
||||
const [uploads, setUploads] = useState<UploadItem[]>([]);
|
||||
|
||||
function updateItem(id: string, patch: Partial<UploadItem>) {
|
||||
setUploads((prev) =>
|
||||
prev.map((item) => (item.id === id ? { ...item, ...patch } : item))
|
||||
);
|
||||
}
|
||||
|
||||
async function uploadFile(uri: string, filename: string, mimeType?: string) {
|
||||
const id = `${Date.now()}-${filename}`;
|
||||
setUploads((prev) => [
|
||||
{ id, filename, status: "uploading" },
|
||||
...prev,
|
||||
]);
|
||||
|
||||
try {
|
||||
const resp = await api.uploadFile(uri, filename, mimeType);
|
||||
updateItem(id, { status: "done", taskId: resp.task_id });
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : "Upload failed";
|
||||
updateItem(id, { status: "error", error: msg });
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCamera() {
|
||||
const { status } = await ImagePicker.requestCameraPermissionsAsync();
|
||||
if (status !== "granted") {
|
||||
Alert.alert(
|
||||
"Camera access required",
|
||||
"Please grant camera access in Settings to capture documents."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ImagePicker.launchCameraAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
quality: 0.9,
|
||||
allowsEditing: false,
|
||||
});
|
||||
|
||||
if (!result.canceled && result.assets.length > 0) {
|
||||
const asset = result.assets[0];
|
||||
const filename = `scan_${Date.now()}.jpg`;
|
||||
await uploadFile(asset.uri, filename, "image/jpeg");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFilePicker() {
|
||||
try {
|
||||
const result = await DocumentPicker.getDocumentAsync({
|
||||
type: "*/*",
|
||||
multiple: true,
|
||||
copyToCacheDirectory: true,
|
||||
});
|
||||
|
||||
if (!result.canceled) {
|
||||
for (const asset of result.assets) {
|
||||
await uploadFile(asset.uri, asset.name, asset.mimeType ?? undefined);
|
||||
}
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
Alert.alert("File picker error", err instanceof Error ? err.message : "Could not open file picker");
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return (
|
||||
<View style={styles.center}>
|
||||
<Text style={styles.emptyText}>Please sign in to upload documents.</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* Action buttons */}
|
||||
<View style={styles.actions}>
|
||||
<Pressable
|
||||
style={[styles.actionButton, styles.cameraButton]}
|
||||
onPress={handleCamera}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Capture document with camera"
|
||||
>
|
||||
<Text style={styles.actionIcon}>📷</Text>
|
||||
<Text style={styles.actionLabel}>Camera</Text>
|
||||
</Pressable>
|
||||
|
||||
<Pressable
|
||||
style={[styles.actionButton, styles.fileButton]}
|
||||
onPress={handleFilePicker}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Pick file from device"
|
||||
>
|
||||
<Text style={styles.actionIcon}>📄</Text>
|
||||
<Text style={styles.actionLabel}>File Picker</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
{/* Upload list */}
|
||||
<ScrollView style={styles.list} contentContainerStyle={styles.listContent}>
|
||||
{uploads.length === 0 ? (
|
||||
<View style={styles.emptyState}>
|
||||
<Text style={styles.emptyEmoji}>☁️</Text>
|
||||
<Text style={styles.emptyText}>
|
||||
Tap Camera or File Picker to upload a document.
|
||||
</Text>
|
||||
<Text style={styles.emptyHint}>
|
||||
You can also share files from other apps directly to DocuElevate.
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
uploads.map((item) => (
|
||||
<UploadRow key={item.id} item={item} />
|
||||
))
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
function UploadRow({ item }: { item: UploadItem }) {
|
||||
const icons: Record<UploadItem["status"], string> = {
|
||||
pending: "⏳",
|
||||
uploading: "⬆️",
|
||||
done: "✅",
|
||||
error: "❌",
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={rowStyles.row}>
|
||||
<Text style={rowStyles.icon}>{icons[item.status]}</Text>
|
||||
<View style={rowStyles.info}>
|
||||
<Text style={rowStyles.filename} numberOfLines={1}>
|
||||
{item.filename}
|
||||
</Text>
|
||||
{item.status === "uploading" && (
|
||||
<ActivityIndicator size="small" color="#1e40af" />
|
||||
)}
|
||||
{item.status === "done" && (
|
||||
<Text style={rowStyles.statusDone}>Queued for processing</Text>
|
||||
)}
|
||||
{item.status === "error" && (
|
||||
<Text style={rowStyles.statusError}>{item.error}</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: "#f9fafb" },
|
||||
actions: {
|
||||
flexDirection: "row",
|
||||
padding: 16,
|
||||
gap: 12,
|
||||
},
|
||||
actionButton: {
|
||||
flex: 1,
|
||||
borderRadius: 12,
|
||||
paddingVertical: 20,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 80,
|
||||
},
|
||||
cameraButton: { backgroundColor: "#1e40af" },
|
||||
fileButton: { backgroundColor: "#059669" },
|
||||
actionIcon: { fontSize: 28, marginBottom: 6 },
|
||||
actionLabel: {
|
||||
color: "#fff",
|
||||
fontSize: 14,
|
||||
fontWeight: "600",
|
||||
},
|
||||
list: { flex: 1 },
|
||||
listContent: { padding: 16 },
|
||||
emptyState: {
|
||||
alignItems: "center",
|
||||
paddingTop: 60,
|
||||
},
|
||||
emptyEmoji: { fontSize: 48, marginBottom: 12 },
|
||||
emptyText: {
|
||||
fontSize: 16,
|
||||
color: "#374151",
|
||||
textAlign: "center",
|
||||
marginBottom: 8,
|
||||
},
|
||||
emptyHint: {
|
||||
fontSize: 13,
|
||||
color: "#6b7280",
|
||||
textAlign: "center",
|
||||
paddingHorizontal: 32,
|
||||
},
|
||||
center: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
});
|
||||
|
||||
const rowStyles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
backgroundColor: "#fff",
|
||||
borderRadius: 10,
|
||||
padding: 14,
|
||||
marginBottom: 10,
|
||||
shadowColor: "#000",
|
||||
shadowOpacity: 0.04,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 4,
|
||||
elevation: 2,
|
||||
},
|
||||
icon: { fontSize: 22, marginRight: 12 },
|
||||
info: { flex: 1 },
|
||||
filename: {
|
||||
fontSize: 14,
|
||||
fontWeight: "600",
|
||||
color: "#111827",
|
||||
marginBottom: 4,
|
||||
},
|
||||
statusDone: { fontSize: 12, color: "#059669" },
|
||||
statusError: { fontSize: 12, color: "#dc2626" },
|
||||
});
|
||||
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* DocuElevate API client for the mobile app.
|
||||
*
|
||||
* All requests authenticate via a Bearer token stored in the device's secure
|
||||
* keychain (via expo-secure-store). The token is obtained once through the
|
||||
* SSO flow and cached until the user explicitly logs out.
|
||||
*/
|
||||
|
||||
import * as SecureStore from "expo-secure-store";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const SECURE_STORE_API_TOKEN_KEY = "de_api_token";
|
||||
export const SECURE_STORE_BASE_URL_KEY = "de_base_url";
|
||||
export const SECURE_STORE_OWNER_ID_KEY = "de_owner_id";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface WhoAmIResponse {
|
||||
owner_id: string;
|
||||
display_name: string | null;
|
||||
email: string | null;
|
||||
avatar_url: string | null;
|
||||
is_admin: boolean;
|
||||
}
|
||||
|
||||
export interface GenerateTokenResponse {
|
||||
token: string;
|
||||
token_id: number;
|
||||
name: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface DeviceRegistration {
|
||||
push_token: string;
|
||||
device_name?: string;
|
||||
platform: "ios" | "android" | "web";
|
||||
}
|
||||
|
||||
export interface FileRecord {
|
||||
id: number;
|
||||
filename: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
file_size: number | null;
|
||||
content_type: string | null;
|
||||
owner_id: string | null;
|
||||
}
|
||||
|
||||
export interface UploadResponse {
|
||||
task_id: string;
|
||||
status: string;
|
||||
message: string;
|
||||
filename: string;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Base API client
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class DocuElevateAPI {
|
||||
private baseUrl: string = "";
|
||||
|
||||
async init(baseUrl: string): Promise<void> {
|
||||
this.baseUrl = baseUrl.replace(/\/$/, "");
|
||||
await SecureStore.setItemAsync(SECURE_STORE_BASE_URL_KEY, this.baseUrl);
|
||||
}
|
||||
|
||||
async loadFromStorage(): Promise<boolean> {
|
||||
try {
|
||||
const url = await SecureStore.getItemAsync(SECURE_STORE_BASE_URL_KEY);
|
||||
if (url) {
|
||||
this.baseUrl = url;
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getBaseUrl(): string {
|
||||
return this.baseUrl;
|
||||
}
|
||||
|
||||
private async getToken(): Promise<string | null> {
|
||||
try {
|
||||
return await SecureStore.getItemAsync(SECURE_STORE_API_TOKEN_KEY);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
method: string,
|
||||
path: string,
|
||||
options?: { body?: unknown; formData?: FormData }
|
||||
): Promise<T> {
|
||||
const token = await this.getToken();
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if (token) {
|
||||
headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
let body: BodyInit | undefined;
|
||||
if (options?.formData) {
|
||||
body = options.formData;
|
||||
// Let fetch set multipart content-type with boundary automatically
|
||||
} else if (options?.body !== undefined) {
|
||||
headers["Content-Type"] = "application/json";
|
||||
body = JSON.stringify(options.body);
|
||||
}
|
||||
|
||||
const response = await fetch(`${this.baseUrl}${path}`, {
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
let detail = `HTTP ${response.status}`;
|
||||
try {
|
||||
const err = await response.json();
|
||||
detail = err.detail || JSON.stringify(err);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
throw new Error(detail);
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
return undefined as unknown as T;
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Auth
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Exchange the current session (cookie) for a long-lived API token. */
|
||||
async generateMobileToken(deviceName: string): Promise<GenerateTokenResponse> {
|
||||
return this.request<GenerateTokenResponse>("POST", "/api/mobile/generate-token", {
|
||||
body: { device_name: deviceName },
|
||||
});
|
||||
}
|
||||
|
||||
/** Return profile information for the authenticated user. */
|
||||
async whoAmI(): Promise<WhoAmIResponse> {
|
||||
return this.request<WhoAmIResponse>("GET", "/api/mobile/whoami");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Push notifications
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Register a push notification device token. */
|
||||
async registerDevice(data: DeviceRegistration): Promise<void> {
|
||||
await this.request("POST", "/api/mobile/register-device", { body: data });
|
||||
}
|
||||
|
||||
/** Deactivate a device registration. */
|
||||
async deactivateDevice(deviceId: number): Promise<void> {
|
||||
await this.request("DELETE", `/api/mobile/devices/${deviceId}`);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Files
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Upload a file for processing. */
|
||||
async uploadFile(uri: string, filename: string, mimeType?: string): Promise<UploadResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append("file", {
|
||||
uri,
|
||||
name: filename,
|
||||
type: mimeType || "application/octet-stream",
|
||||
} as unknown as Blob);
|
||||
|
||||
return this.request<UploadResponse>("POST", "/api/ui-upload", { formData });
|
||||
}
|
||||
|
||||
/** List recently processed files. */
|
||||
async listFiles(page = 1, pageSize = 20): Promise<FileRecord[]> {
|
||||
return this.request<FileRecord[]>(
|
||||
"GET",
|
||||
`/api/files?page=${page}&page_size=${pageSize}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const api = new DocuElevateAPI();
|
||||
export default api;
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": ["ESNext"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react-native",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
+4
-1
@@ -51,4 +51,7 @@ meilisearch>=0.31.0 # Full-text search engine client
|
||||
stripe>=7.0.0,<15.0.0 # Stripe billing SDK (MIT license)
|
||||
|
||||
# Error and performance monitoring
|
||||
sentry-sdk[fastapi,celery,sqlalchemy]>=2.20.0,<3.0.0
|
||||
sentry-sdk[fastapi,celery,sqlalchemy]>=2.20.0,<3.0.0
|
||||
|
||||
# GraphQL API
|
||||
strawberry-graphql[fastapi]>=0.243.0,<1.0.0
|
||||
|
||||
@@ -61,6 +61,7 @@ from app.main import app as fastapi_app # noqa: E402
|
||||
# Import models to register them with SQLAlchemy Base
|
||||
from app.models import ( # noqa: F401, E402
|
||||
ApiToken,
|
||||
AuditLog,
|
||||
ComplianceTemplate,
|
||||
DocumentMetadata,
|
||||
FileRecord,
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
"""Tests for the mobile API endpoints (app/api/mobile.py)."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from app.database import Base, get_db
|
||||
from app.models import ApiToken, MobileDevice
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test data
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_OWNER = "mobile_user@example.com"
|
||||
_OTHER_OWNER = "other@example.com"
|
||||
_EXPO_TOKEN = "ExponentPushToken[test-token-abc123]"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def mob_engine():
|
||||
"""In-memory SQLite engine for mobile tests."""
|
||||
engine = create_engine(
|
||||
"sqlite:///:memory:",
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
yield engine
|
||||
Base.metadata.drop_all(bind=engine)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def mob_session(mob_engine):
|
||||
"""DB session scoped to one test."""
|
||||
Session = sessionmaker(bind=mob_engine)
|
||||
session = Session()
|
||||
yield session
|
||||
session.close()
|
||||
|
||||
|
||||
def _make_client(mob_engine, owner_id: str = _OWNER) -> TestClient:
|
||||
"""Return a TestClient with *owner_id* injected as the authenticated user."""
|
||||
from app.api.mobile import _get_owner_id
|
||||
from app.main import app
|
||||
|
||||
Session = sessionmaker(bind=mob_engine)
|
||||
|
||||
def _override_get_db():
|
||||
session = Session()
|
||||
try:
|
||||
yield session
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def _override_owner():
|
||||
return owner_id
|
||||
|
||||
app.dependency_overrides[get_db] = _override_get_db
|
||||
app.dependency_overrides[_get_owner_id] = _override_owner
|
||||
|
||||
client = TestClient(app, base_url="http://localhost", raise_server_exceptions=False)
|
||||
return client
|
||||
|
||||
|
||||
def _cleanup(app):
|
||||
"""Remove dependency overrides after test."""
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests – /mobile/generate-token
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestGenerateMobileToken:
|
||||
"""Tests for POST /api/mobile/generate-token."""
|
||||
|
||||
def test_generate_token_success(self, mob_engine):
|
||||
"""Generating a mobile token returns a token string and metadata."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.post(
|
||||
"/api/mobile/generate-token",
|
||||
json={"device_name": "John's iPhone"},
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
data = resp.json()
|
||||
assert data["token"].startswith("de_")
|
||||
assert data["token_id"] > 0
|
||||
assert "Mobile App" in data["name"]
|
||||
assert "John's iPhone" in data["name"]
|
||||
assert "created_at" in data
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_generate_token_default_device_name(self, mob_engine):
|
||||
"""A default device name is used if none is provided."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.post("/api/mobile/generate-token", json={})
|
||||
assert resp.status_code == 201
|
||||
data = resp.json()
|
||||
assert "Mobile App" in data["name"]
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_generate_token_persisted_in_db(self, mob_engine, mob_session):
|
||||
"""The generated token is stored in the api_tokens table."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.post(
|
||||
"/api/mobile/generate-token",
|
||||
json={"device_name": "Test Device"},
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
token_id = resp.json()["token_id"]
|
||||
|
||||
db_token = mob_session.get(ApiToken, token_id)
|
||||
assert db_token is not None
|
||||
assert db_token.owner_id == _OWNER
|
||||
assert "Mobile App" in db_token.name
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_generate_token_unauthenticated(self, mob_engine):
|
||||
"""Unauthenticated requests are rejected with 401."""
|
||||
from app.api.mobile import _get_owner_id
|
||||
from app.main import app
|
||||
|
||||
Session = sessionmaker(bind=mob_engine)
|
||||
|
||||
def _override_get_db():
|
||||
session = Session()
|
||||
try:
|
||||
yield session
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def _raise_401():
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated")
|
||||
|
||||
app.dependency_overrides[get_db] = _override_get_db
|
||||
app.dependency_overrides[_get_owner_id] = _raise_401
|
||||
|
||||
client = TestClient(app, base_url="http://localhost", raise_server_exceptions=False)
|
||||
try:
|
||||
resp = client.post("/api/mobile/generate-token", json={"device_name": "Test"})
|
||||
assert resp.status_code == 401
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests – /mobile/register-device
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestRegisterDevice:
|
||||
"""Tests for POST /api/mobile/register-device."""
|
||||
|
||||
def test_register_new_device(self, mob_engine, mob_session):
|
||||
"""Registering a new device persists it in mobile_devices."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.post(
|
||||
"/api/mobile/register-device",
|
||||
json={
|
||||
"push_token": _EXPO_TOKEN,
|
||||
"device_name": "Test iPhone",
|
||||
"platform": "ios",
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
data = resp.json()
|
||||
assert data["id"] > 0
|
||||
assert data["platform"] == "ios"
|
||||
assert data["is_active"] is True
|
||||
assert "ExponentPushToken" in data["push_token_preview"]
|
||||
|
||||
device = mob_session.get(MobileDevice, data["id"])
|
||||
assert device is not None
|
||||
assert device.push_token == _EXPO_TOKEN
|
||||
assert device.owner_id == _OWNER
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_register_same_token_is_idempotent(self, mob_engine, mob_session):
|
||||
"""Re-registering the same token reactivates the existing record."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp1 = client.post(
|
||||
"/api/mobile/register-device",
|
||||
json={"push_token": _EXPO_TOKEN, "platform": "ios"},
|
||||
)
|
||||
assert resp1.status_code == 201
|
||||
id1 = resp1.json()["id"]
|
||||
|
||||
resp2 = client.post(
|
||||
"/api/mobile/register-device",
|
||||
json={"push_token": _EXPO_TOKEN, "device_name": "Updated Name", "platform": "ios"},
|
||||
)
|
||||
assert resp2.status_code == 201
|
||||
id2 = resp2.json()["id"]
|
||||
|
||||
assert id1 == id2 # Same record reused
|
||||
|
||||
devices = mob_session.query(MobileDevice).filter(MobileDevice.owner_id == _OWNER).all()
|
||||
assert len(devices) == 1
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_register_invalid_platform(self, mob_engine):
|
||||
"""An invalid platform value is rejected with 422."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.post(
|
||||
"/api/mobile/register-device",
|
||||
json={"push_token": _EXPO_TOKEN, "platform": "windows"},
|
||||
)
|
||||
assert resp.status_code == 422
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_register_android_device(self, mob_engine):
|
||||
"""Android devices can be registered."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.post(
|
||||
"/api/mobile/register-device",
|
||||
json={
|
||||
"push_token": "ExponentPushToken[android-token-xyz]",
|
||||
"device_name": "Pixel 8",
|
||||
"platform": "android",
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
assert resp.json()["platform"] == "android"
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests – /mobile/devices
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestListDevices:
|
||||
"""Tests for GET /api/mobile/devices."""
|
||||
|
||||
def test_list_devices_empty(self, mob_engine):
|
||||
"""An empty list is returned when no devices are registered."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.get("/api/mobile/devices")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == []
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_list_devices_returns_own_devices_only(self, mob_engine, mob_session):
|
||||
"""Only the current user's devices are returned."""
|
||||
from app.main import app
|
||||
|
||||
# Add devices for two different owners directly
|
||||
mob_session.add(
|
||||
MobileDevice(
|
||||
owner_id=_OWNER,
|
||||
push_token="ExponentPushToken[owner-token-12345]",
|
||||
platform="ios",
|
||||
)
|
||||
)
|
||||
mob_session.add(
|
||||
MobileDevice(
|
||||
owner_id=_OTHER_OWNER,
|
||||
push_token="ExponentPushToken[other-token-67890]",
|
||||
platform="android",
|
||||
)
|
||||
)
|
||||
mob_session.commit()
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.get("/api/mobile/devices")
|
||||
assert resp.status_code == 200
|
||||
devices = resp.json()
|
||||
assert len(devices) == 1
|
||||
# The push_token_preview is the first 20 chars + "…"
|
||||
assert devices[0]["push_token_preview"].startswith("ExponentPushToken[ow")
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests – DELETE /mobile/devices/{device_id}
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestDeactivateDevice:
|
||||
"""Tests for DELETE /api/mobile/devices/{device_id}."""
|
||||
|
||||
def test_deactivate_own_device(self, mob_engine, mob_session):
|
||||
"""Deactivating a device sets is_active to False."""
|
||||
from app.main import app
|
||||
|
||||
device = MobileDevice(
|
||||
owner_id=_OWNER,
|
||||
push_token=_EXPO_TOKEN,
|
||||
platform="ios",
|
||||
is_active=True,
|
||||
)
|
||||
mob_session.add(device)
|
||||
mob_session.commit()
|
||||
mob_session.refresh(device)
|
||||
device_id = device.id
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.delete(f"/api/mobile/devices/{device_id}")
|
||||
assert resp.status_code == 204
|
||||
|
||||
mob_session.expire_all()
|
||||
updated = mob_session.get(MobileDevice, device_id)
|
||||
assert updated is not None
|
||||
assert updated.is_active is False
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_deactivate_other_users_device_returns_404(self, mob_engine, mob_session):
|
||||
"""Attempting to deactivate another user's device returns 404."""
|
||||
from app.main import app
|
||||
|
||||
device = MobileDevice(
|
||||
owner_id=_OTHER_OWNER,
|
||||
push_token="ExponentPushToken[other-token]",
|
||||
platform="ios",
|
||||
is_active=True,
|
||||
)
|
||||
mob_session.add(device)
|
||||
mob_session.commit()
|
||||
mob_session.refresh(device)
|
||||
device_id = device.id
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.delete(f"/api/mobile/devices/{device_id}")
|
||||
assert resp.status_code == 404
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_deactivate_nonexistent_device_returns_404(self, mob_engine):
|
||||
"""Deactivating a device that does not exist returns 404."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.delete("/api/mobile/devices/99999")
|
||||
assert resp.status_code == 404
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests – /mobile/whoami
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestWhoAmI:
|
||||
"""Tests for GET /api/mobile/whoami."""
|
||||
|
||||
def test_whoami_with_no_profile(self, mob_engine):
|
||||
"""Returns owner_id and inferred email even when no UserProfile exists."""
|
||||
from app.main import app
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.get("/api/mobile/whoami")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["owner_id"] == _OWNER
|
||||
assert data["display_name"] is None
|
||||
# _OWNER contains "@" so email is inferred from owner_id
|
||||
assert data["email"] == _OWNER
|
||||
assert data["avatar_url"] is not None # Gravatar URL from email
|
||||
assert data["is_admin"] is False
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
def test_whoami_with_profile(self, mob_engine, mob_session):
|
||||
"""Returns full profile data when a UserProfile record exists."""
|
||||
from app.main import app
|
||||
from app.models import UserProfile
|
||||
|
||||
profile = UserProfile(
|
||||
user_id=_OWNER,
|
||||
display_name="Alice Test",
|
||||
)
|
||||
mob_session.add(profile)
|
||||
mob_session.commit()
|
||||
|
||||
client = _make_client(mob_engine)
|
||||
try:
|
||||
resp = client.get("/api/mobile/whoami")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["owner_id"] == _OWNER
|
||||
assert data["display_name"] == "Alice Test"
|
||||
# owner_id contains "@" so email is inferred from it
|
||||
assert data["email"] == _OWNER
|
||||
assert data["avatar_url"] is not None # Gravatar URL
|
||||
assert data["is_admin"] is False
|
||||
finally:
|
||||
_cleanup(app)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests – push notification utility
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestPushNotificationUtility:
|
||||
"""Tests for app/utils/push_notification.py."""
|
||||
|
||||
def test_send_expo_push_empty_tokens(self):
|
||||
"""send_expo_push_notification with no tokens returns empty list."""
|
||||
from app.utils.push_notification import send_expo_push_notification
|
||||
|
||||
result = send_expo_push_notification([], "Title", "Body")
|
||||
assert result == []
|
||||
|
||||
def test_send_expo_push_calls_expo_api(self):
|
||||
"""send_expo_push_notification POSTs to the Expo push API."""
|
||||
from app.utils.push_notification import send_expo_push_notification
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = {"data": [{"status": "ok"}]}
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
|
||||
with patch("app.utils.push_notification.httpx.post", return_value=mock_response) as mock_post:
|
||||
result = send_expo_push_notification(
|
||||
tokens=["ExponentPushToken[abc]"],
|
||||
title="Test",
|
||||
body="Message",
|
||||
)
|
||||
|
||||
mock_post.assert_called_once()
|
||||
call_kwargs = mock_post.call_args
|
||||
assert "exp.host" in call_kwargs[0][0]
|
||||
payload = call_kwargs[1]["json"]
|
||||
assert len(payload) == 1
|
||||
assert payload[0]["to"] == "ExponentPushToken[abc]"
|
||||
assert payload[0]["title"] == "Test"
|
||||
|
||||
def test_send_push_to_owner_no_devices(self, mob_engine):
|
||||
"""send_push_to_owner silently does nothing when no devices are registered."""
|
||||
from app.utils.push_notification import send_push_to_owner
|
||||
|
||||
mock_session = MagicMock()
|
||||
mock_session.query.return_value.filter.return_value.all.return_value = []
|
||||
mock_session.close = MagicMock()
|
||||
|
||||
with patch("app.utils.push_notification.SessionLocal", return_value=mock_session):
|
||||
with patch("app.utils.push_notification.send_expo_push_notification") as mock_send:
|
||||
send_push_to_owner("user@example.com", "Title", "Body")
|
||||
mock_send.assert_not_called()
|
||||
mock_session.close.assert_called_once()
|
||||
|
||||
def test_send_push_to_owner_with_devices(self):
|
||||
"""send_push_to_owner calls send_expo_push_notification with device tokens."""
|
||||
from app.utils.push_notification import send_push_to_owner
|
||||
|
||||
fake_device = MagicMock()
|
||||
fake_device.push_token = "ExponentPushToken[device1]"
|
||||
fake_device.is_active = True
|
||||
|
||||
mock_session = MagicMock()
|
||||
mock_session.query.return_value.filter.return_value.all.return_value = [fake_device]
|
||||
mock_session.close = MagicMock()
|
||||
|
||||
with patch("app.utils.push_notification.SessionLocal", return_value=mock_session):
|
||||
with patch("app.utils.push_notification.send_expo_push_notification") as mock_send:
|
||||
mock_send.return_value = [{"status": "ok"}]
|
||||
send_push_to_owner("user@example.com", "Processed!", "Your doc is ready.")
|
||||
|
||||
mock_send.assert_called_once()
|
||||
call_kwargs = mock_send.call_args[1]
|
||||
assert "ExponentPushToken[device1]" in call_kwargs["tokens"]
|
||||
@@ -0,0 +1,365 @@
|
||||
"""
|
||||
Tests for the comprehensive audit logging feature.
|
||||
|
||||
Covers the audit service (recording, querying, SIEM forwarding),
|
||||
the REST API endpoints, and the admin viewer page.
|
||||
"""
|
||||
|
||||
import json
|
||||
import socket
|
||||
from datetime import datetime, timezone
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from app.database import Base
|
||||
from app.models import AuditLog
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def audit_db():
|
||||
"""Fresh in-memory database with all tables created."""
|
||||
engine = create_engine(
|
||||
"sqlite:///:memory:",
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
Session = sessionmaker(bind=engine)
|
||||
session = Session()
|
||||
yield session
|
||||
session.close()
|
||||
Base.metadata.drop_all(bind=engine)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Model tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestAuditLogModel:
|
||||
"""Verify the AuditLog ORM model."""
|
||||
|
||||
def test_create_minimal_entry(self, audit_db):
|
||||
"""Minimal required fields can be persisted."""
|
||||
entry = AuditLog(user="alice", action="login")
|
||||
audit_db.add(entry)
|
||||
audit_db.commit()
|
||||
audit_db.refresh(entry)
|
||||
assert entry.id is not None
|
||||
assert entry.user == "alice"
|
||||
assert entry.action == "login"
|
||||
assert entry.severity == "info" # server default
|
||||
|
||||
def test_create_full_entry(self, audit_db):
|
||||
"""All columns persist correctly."""
|
||||
entry = AuditLog(
|
||||
user="bob",
|
||||
action="document.create",
|
||||
resource_type="document",
|
||||
resource_id="42",
|
||||
ip_address="10.0.0.1",
|
||||
details='{"filename": "invoice.pdf"}',
|
||||
severity="warning",
|
||||
)
|
||||
audit_db.add(entry)
|
||||
audit_db.commit()
|
||||
audit_db.refresh(entry)
|
||||
assert entry.resource_type == "document"
|
||||
assert entry.resource_id == "42"
|
||||
assert entry.ip_address == "10.0.0.1"
|
||||
assert json.loads(entry.details) == {"filename": "invoice.pdf"}
|
||||
assert entry.severity == "warning"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Service tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestAuditService:
|
||||
"""Verify the audit_service helper functions."""
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_record_event(self, mock_settings, audit_db):
|
||||
"""record_event persists a row and returns the entry."""
|
||||
mock_settings.audit_siem_enabled = False
|
||||
from app.utils.audit_service import record_event
|
||||
|
||||
entry = record_event(
|
||||
audit_db,
|
||||
action="settings.update",
|
||||
user="admin",
|
||||
resource_type="settings",
|
||||
resource_id="openai_model",
|
||||
details={"old": "gpt-4", "new": "gpt-4o"},
|
||||
)
|
||||
assert entry.id is not None
|
||||
assert entry.action == "settings.update"
|
||||
assert entry.user == "admin"
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_query_events_no_filter(self, mock_settings, audit_db):
|
||||
"""query_events returns all events when no filter is supplied."""
|
||||
mock_settings.audit_siem_enabled = False
|
||||
from app.utils.audit_service import query_events, record_event
|
||||
|
||||
for i in range(5):
|
||||
record_event(audit_db, action=f"action_{i}", user="sys")
|
||||
results = query_events(audit_db)
|
||||
assert len(results) == 5
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_query_events_filter_action(self, mock_settings, audit_db):
|
||||
"""query_events filters by action."""
|
||||
mock_settings.audit_siem_enabled = False
|
||||
from app.utils.audit_service import query_events, record_event
|
||||
|
||||
record_event(audit_db, action="login", user="alice")
|
||||
record_event(audit_db, action="logout", user="alice")
|
||||
results = query_events(audit_db, action="login")
|
||||
assert len(results) == 1
|
||||
assert results[0].action == "login"
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_query_events_filter_user(self, mock_settings, audit_db):
|
||||
"""query_events filters by user."""
|
||||
mock_settings.audit_siem_enabled = False
|
||||
from app.utils.audit_service import query_events, record_event
|
||||
|
||||
record_event(audit_db, action="login", user="alice")
|
||||
record_event(audit_db, action="login", user="bob")
|
||||
results = query_events(audit_db, user="bob")
|
||||
assert len(results) == 1
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_query_events_filter_severity(self, mock_settings, audit_db):
|
||||
"""query_events filters by severity."""
|
||||
mock_settings.audit_siem_enabled = False
|
||||
from app.utils.audit_service import query_events, record_event
|
||||
|
||||
record_event(audit_db, action="fail", user="sys", severity="error")
|
||||
record_event(audit_db, action="ok", user="sys", severity="info")
|
||||
results = query_events(audit_db, severity="error")
|
||||
assert len(results) == 1
|
||||
assert results[0].severity == "error"
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_count_events(self, mock_settings, audit_db):
|
||||
"""count_events returns the correct total."""
|
||||
mock_settings.audit_siem_enabled = False
|
||||
from app.utils.audit_service import count_events, record_event
|
||||
|
||||
for _ in range(3):
|
||||
record_event(audit_db, action="ping", user="sys")
|
||||
assert count_events(audit_db) == 3
|
||||
assert count_events(audit_db, action="ping") == 3
|
||||
assert count_events(audit_db, action="pong") == 0
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_query_events_pagination(self, mock_settings, audit_db):
|
||||
"""query_events respects limit and offset."""
|
||||
mock_settings.audit_siem_enabled = False
|
||||
from app.utils.audit_service import query_events, record_event
|
||||
|
||||
for i in range(10):
|
||||
record_event(audit_db, action=f"a{i}", user="sys")
|
||||
page1 = query_events(audit_db, limit=3, offset=0)
|
||||
page2 = query_events(audit_db, limit=3, offset=3)
|
||||
assert len(page1) == 3
|
||||
assert len(page2) == 3
|
||||
assert page1[0].id != page2[0].id
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SIEM forwarding tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestSIEMForwarding:
|
||||
"""Verify SIEM transport helpers."""
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
def test_build_siem_payload(self, mock_settings):
|
||||
"""_build_siem_payload returns a dict with all expected keys."""
|
||||
from app.utils.audit_service import _build_siem_payload
|
||||
|
||||
entry = AuditLog(
|
||||
id=1,
|
||||
user="admin",
|
||||
action="login",
|
||||
resource_type="session",
|
||||
timestamp=datetime(2026, 1, 1, tzinfo=timezone.utc),
|
||||
severity="info",
|
||||
)
|
||||
payload = _build_siem_payload(entry)
|
||||
assert payload["user"] == "admin"
|
||||
assert payload["action"] == "login"
|
||||
assert payload["source"] == "docuelevate"
|
||||
assert "timestamp" in payload
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
@patch("app.utils.audit_service.socket")
|
||||
def test_send_syslog_udp(self, mock_socket_mod, mock_settings):
|
||||
"""_send_syslog sends a UDP datagram to the configured host."""
|
||||
mock_settings.audit_siem_syslog_protocol = "udp"
|
||||
mock_settings.audit_siem_syslog_host = "127.0.0.1"
|
||||
mock_settings.audit_siem_syslog_port = 5140
|
||||
|
||||
mock_sock = MagicMock()
|
||||
mock_socket_mod.AF_INET = socket.AF_INET
|
||||
mock_socket_mod.SOCK_DGRAM = socket.SOCK_DGRAM
|
||||
mock_socket_mod.gethostname.return_value = "test-host"
|
||||
mock_socket_mod.socket.return_value.__enter__ = MagicMock(return_value=mock_sock)
|
||||
mock_socket_mod.socket.return_value.__exit__ = MagicMock(return_value=False)
|
||||
|
||||
from app.utils.audit_service import _send_syslog
|
||||
|
||||
_send_syslog({"user": "test", "action": "login", "severity": "info", "timestamp": "2026-01-01T00:00:00"})
|
||||
mock_sock.sendto.assert_called_once()
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
@patch("app.utils.audit_service.httpx")
|
||||
def test_send_http_generic(self, mock_httpx, mock_settings):
|
||||
"""_send_http POSTs JSON to a generic endpoint."""
|
||||
mock_settings.audit_siem_http_url = "https://siem.example.com/ingest"
|
||||
mock_settings.audit_siem_http_token = "my-token"
|
||||
mock_settings.audit_siem_http_custom_headers = ""
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.status_code = 200
|
||||
mock_client.post.return_value = mock_resp
|
||||
mock_httpx.Client.return_value.__enter__ = MagicMock(return_value=mock_client)
|
||||
mock_httpx.Client.return_value.__exit__ = MagicMock(return_value=False)
|
||||
|
||||
from app.utils.audit_service import _send_http
|
||||
|
||||
_send_http({"user": "test", "action": "login"})
|
||||
mock_client.post.assert_called_once()
|
||||
call_kwargs = mock_client.post.call_args
|
||||
assert call_kwargs.kwargs["headers"]["Authorization"] == "Bearer my-token"
|
||||
|
||||
@patch("app.utils.audit_service.settings")
|
||||
@patch("app.utils.audit_service.httpx")
|
||||
def test_send_http_splunk_hec(self, mock_httpx, mock_settings):
|
||||
"""_send_http wraps payload in Splunk HEC envelope when URL contains /services/collector."""
|
||||
mock_settings.audit_siem_http_url = "https://splunk:8088/services/collector/event"
|
||||
mock_settings.audit_siem_http_token = "hec-token"
|
||||
mock_settings.audit_siem_http_custom_headers = ""
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_resp = MagicMock()
|
||||
mock_resp.status_code = 200
|
||||
mock_client.post.return_value = mock_resp
|
||||
mock_httpx.Client.return_value.__enter__ = MagicMock(return_value=mock_client)
|
||||
mock_httpx.Client.return_value.__exit__ = MagicMock(return_value=False)
|
||||
|
||||
from app.utils.audit_service import _send_http
|
||||
|
||||
_send_http({"user": "test", "action": "login"})
|
||||
call_kwargs = mock_client.post.call_args
|
||||
body = call_kwargs.kwargs["json"]
|
||||
assert "event" in body
|
||||
assert body["sourcetype"] == "docuelevate:audit"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# API endpoint tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
class TestAuditLogAPI:
|
||||
"""Test /api/audit-logs REST endpoints."""
|
||||
|
||||
def test_list_audit_logs_empty(self, client):
|
||||
"""GET /api/audit-logs returns empty list when no events exist."""
|
||||
resp = client.get("/api/audit-logs")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["items"] == []
|
||||
assert data["total"] == 0
|
||||
|
||||
def test_list_audit_logs_with_data(self, client, db_session):
|
||||
"""GET /api/audit-logs returns recorded events."""
|
||||
entry = AuditLog(user="tester", action="test.action", severity="info")
|
||||
db_session.add(entry)
|
||||
db_session.commit()
|
||||
|
||||
resp = client.get("/api/audit-logs")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["total"] == 1
|
||||
assert data["items"][0]["action"] == "test.action"
|
||||
|
||||
def test_list_audit_logs_filter_by_action(self, client, db_session):
|
||||
"""GET /api/audit-logs?action=x filters correctly."""
|
||||
db_session.add(AuditLog(user="a", action="login", severity="info"))
|
||||
db_session.add(AuditLog(user="a", action="logout", severity="info"))
|
||||
db_session.commit()
|
||||
|
||||
resp = client.get("/api/audit-logs?action=login")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["total"] == 1
|
||||
|
||||
def test_list_distinct_actions(self, client, db_session):
|
||||
"""GET /api/audit-logs/actions returns distinct action values."""
|
||||
db_session.add(AuditLog(user="a", action="login", severity="info"))
|
||||
db_session.add(AuditLog(user="b", action="login", severity="info"))
|
||||
db_session.add(AuditLog(user="a", action="logout", severity="info"))
|
||||
db_session.commit()
|
||||
|
||||
resp = client.get("/api/audit-logs/actions")
|
||||
assert resp.status_code == 200
|
||||
actions = resp.json()
|
||||
assert set(actions) == {"login", "logout"}
|
||||
|
||||
def test_list_distinct_users(self, client, db_session):
|
||||
"""GET /api/audit-logs/users returns distinct user values."""
|
||||
db_session.add(AuditLog(user="alice", action="x", severity="info"))
|
||||
db_session.add(AuditLog(user="bob", action="x", severity="info"))
|
||||
db_session.commit()
|
||||
|
||||
resp = client.get("/api/audit-logs/users")
|
||||
assert resp.status_code == 200
|
||||
users = resp.json()
|
||||
assert set(users) == {"alice", "bob"}
|
||||
|
||||
def test_list_audit_logs_pagination(self, client, db_session):
|
||||
"""GET /api/audit-logs supports limit/offset pagination."""
|
||||
for i in range(5):
|
||||
db_session.add(AuditLog(user="u", action=f"a{i}", severity="info"))
|
||||
db_session.commit()
|
||||
|
||||
resp = client.get("/api/audit-logs?limit=2&offset=0")
|
||||
data = resp.json()
|
||||
assert len(data["items"]) == 2
|
||||
assert data["total"] == 5
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# View tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
class TestAuditLogView:
|
||||
"""Test the admin audit-log viewer page."""
|
||||
|
||||
def test_audit_logs_page_loads(self, client):
|
||||
"""GET /admin/audit-logs returns 200 and renders the template."""
|
||||
resp = client.get("/admin/audit-logs")
|
||||
assert resp.status_code == 200
|
||||
assert "Audit Logs" in resp.text
|
||||
@@ -124,6 +124,85 @@ class TestInitDb:
|
||||
|
||||
test_engine.dispose()
|
||||
|
||||
def test_init_db_creates_shared_links_for_database_missing_table(self, tmp_path):
|
||||
"""Regression test: databases at revision 026 that skipped 025_add_shared_links.
|
||||
|
||||
Migration 025_add_shared_links was inserted into the chain between
|
||||
024_add_api_tokens and 025_add_user_notifications after some databases
|
||||
had already been migrated past that point. Migration 027 creates the
|
||||
table idempotently so those databases are repaired.
|
||||
"""
|
||||
from sqlalchemy import create_engine, text
|
||||
from sqlalchemy import inspect as sa_inspect
|
||||
|
||||
db_path = str(tmp_path / "regression_shared_links.db")
|
||||
test_engine = create_engine(f"sqlite:///{db_path}")
|
||||
|
||||
# Set up a database at revision 026 but WITHOUT the shared_links table.
|
||||
# This simulates a DB that was migrated before 025_add_shared_links
|
||||
# was inserted into the chain.
|
||||
with test_engine.begin() as conn:
|
||||
conn.execute(
|
||||
text(
|
||||
"CREATE TABLE files ("
|
||||
"id INTEGER PRIMARY KEY, filehash VARCHAR NOT NULL, "
|
||||
"original_filename VARCHAR, local_filename VARCHAR NOT NULL, "
|
||||
"original_file_path VARCHAR, processed_file_path VARCHAR, "
|
||||
"file_size INTEGER NOT NULL, mime_type VARCHAR, "
|
||||
"is_duplicate BOOLEAN DEFAULT 0 NOT NULL, duplicate_of_id INTEGER, "
|
||||
"ocr_text TEXT, ai_metadata TEXT, document_title VARCHAR, "
|
||||
"ocr_quality_score INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)"
|
||||
)
|
||||
)
|
||||
conn.execute(
|
||||
text(
|
||||
"CREATE TABLE processing_logs ("
|
||||
"id INTEGER PRIMARY KEY, file_id INTEGER, task_id VARCHAR, "
|
||||
"step_name VARCHAR, status VARCHAR, message VARCHAR, detail TEXT, "
|
||||
"timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)"
|
||||
)
|
||||
)
|
||||
conn.execute(
|
||||
text(
|
||||
"CREATE TABLE file_processing_steps ("
|
||||
"id INTEGER PRIMARY KEY, file_id INTEGER NOT NULL, "
|
||||
"step_name VARCHAR NOT NULL, status VARCHAR NOT NULL, "
|
||||
"started_at DATETIME, completed_at DATETIME, error_message TEXT, "
|
||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
|
||||
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP)"
|
||||
)
|
||||
)
|
||||
conn.execute(
|
||||
text(
|
||||
"CREATE TABLE saved_searches ("
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, user_id VARCHAR NOT NULL, "
|
||||
"name VARCHAR NOT NULL, filters TEXT NOT NULL, "
|
||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
|
||||
"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
|
||||
"UNIQUE (user_id, name))"
|
||||
)
|
||||
)
|
||||
conn.execute(text("CREATE TABLE alembic_version (version_num VARCHAR(32) NOT NULL)"))
|
||||
conn.execute(text("INSERT INTO alembic_version VALUES ('026_add_scheduled_jobs')"))
|
||||
|
||||
with patch("app.database.engine", test_engine), patch("app.database.DB_URL", f"sqlite:///{db_path}"):
|
||||
init_db()
|
||||
|
||||
inspector = sa_inspect(test_engine)
|
||||
table_names = inspector.get_table_names()
|
||||
assert "shared_links" in table_names
|
||||
|
||||
# Verify the shared_links table has the expected columns.
|
||||
columns = {col["name"] for col in inspector.get_columns("shared_links")}
|
||||
assert "id" in columns
|
||||
assert "token" in columns
|
||||
assert "file_id" in columns
|
||||
assert "owner_id" in columns
|
||||
assert "expires_at" in columns
|
||||
assert "is_active" in columns
|
||||
|
||||
test_engine.dispose()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestGetDb:
|
||||
|
||||
@@ -0,0 +1,419 @@
|
||||
"""
|
||||
Tests for the GraphQL API endpoint at /graphql.
|
||||
|
||||
Covers:
|
||||
- Schema introspection (endpoint availability + GraphiQL)
|
||||
- Query: documents (list, single, auth-gated)
|
||||
- Query: pipelines (list, single)
|
||||
- Query: settings (admin-only)
|
||||
- Query: users (admin-only)
|
||||
- Pagination and limit clamping
|
||||
- Sensitive setting keys are excluded
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.models import ApplicationSettings, FileRecord, Pipeline, PipelineStep, UserProfile
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def gql(client: TestClient, query: str, variables: dict | None = None) -> dict:
|
||||
"""Execute a GraphQL POST request and return the parsed JSON body."""
|
||||
payload: dict = {"query": query}
|
||||
if variables:
|
||||
payload["variables"] = variables
|
||||
response = client.post("/graphql", json=payload)
|
||||
assert response.status_code == 200, f"Unexpected status {response.status_code}: {response.text}"
|
||||
return response.json()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def file_record(db_session) -> FileRecord:
|
||||
rec = FileRecord(
|
||||
owner_id="user1",
|
||||
original_filename="invoice.pdf",
|
||||
local_filename="/workdir/tmp/invoice.pdf",
|
||||
file_size=1024,
|
||||
mime_type="application/pdf",
|
||||
filehash="abc123",
|
||||
)
|
||||
db_session.add(rec)
|
||||
db_session.commit()
|
||||
db_session.refresh(rec)
|
||||
return rec
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def pipeline_record(db_session) -> Pipeline:
|
||||
p = Pipeline(
|
||||
owner_id="user1",
|
||||
name="Test Pipeline",
|
||||
description="A pipeline for tests",
|
||||
is_default=False,
|
||||
is_active=True,
|
||||
)
|
||||
db_session.add(p)
|
||||
db_session.commit()
|
||||
db_session.refresh(p)
|
||||
|
||||
step = PipelineStep(
|
||||
pipeline_id=p.id,
|
||||
position=0,
|
||||
step_type="ocr",
|
||||
label="Run OCR",
|
||||
enabled=True,
|
||||
)
|
||||
db_session.add(step)
|
||||
db_session.commit()
|
||||
return p
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def setting_record(db_session) -> ApplicationSettings:
|
||||
s = ApplicationSettings(key="max_upload_size", value="104857600")
|
||||
db_session.add(s)
|
||||
db_session.commit()
|
||||
db_session.refresh(s)
|
||||
return s
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def user_profile(db_session) -> UserProfile:
|
||||
profile = UserProfile(
|
||||
user_id="user1",
|
||||
display_name="Test User",
|
||||
is_blocked=False,
|
||||
subscription_tier="free",
|
||||
onboarding_completed=False,
|
||||
)
|
||||
db_session.add(profile)
|
||||
db_session.commit()
|
||||
db_session.refresh(profile)
|
||||
return profile
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: endpoint availability
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestGraphQLEndpoint:
|
||||
"""Verify the /graphql endpoint is reachable and introspectable."""
|
||||
|
||||
def test_graphql_post_exists(self, client: TestClient):
|
||||
"""POST /graphql returns 200 for a valid introspection query."""
|
||||
result = gql(client, "{ __schema { queryType { name } } }")
|
||||
assert "data" in result
|
||||
assert result["data"]["__schema"]["queryType"]["name"] == "Query"
|
||||
|
||||
def test_graphql_get_returns_graphiql(self, client: TestClient):
|
||||
"""GET /graphql returns the GraphiQL playground HTML."""
|
||||
response = client.get("/graphql", headers={"Accept": "text/html"})
|
||||
assert response.status_code == 200
|
||||
assert "graphiql" in response.text.lower() or "graphql" in response.text.lower()
|
||||
|
||||
def test_graphql_schema_has_expected_types(self, client: TestClient):
|
||||
"""Schema exposes DocumentType, PipelineType, SettingType, UserType."""
|
||||
result = gql(
|
||||
client,
|
||||
"""
|
||||
{
|
||||
__schema {
|
||||
types { name }
|
||||
}
|
||||
}
|
||||
""",
|
||||
)
|
||||
type_names = {t["name"] for t in result["data"]["__schema"]["types"]}
|
||||
for expected in ("DocumentType", "PipelineType", "SettingType", "UserType"):
|
||||
assert expected in type_names, f"{expected} not found in schema"
|
||||
|
||||
def test_graphql_query_fields(self, client: TestClient):
|
||||
"""Root Query has documents, document, pipelines, pipeline, settings, users, user fields."""
|
||||
result = gql(
|
||||
client,
|
||||
"""
|
||||
{
|
||||
__type(name: "Query") {
|
||||
fields { name }
|
||||
}
|
||||
}
|
||||
""",
|
||||
)
|
||||
field_names = {f["name"] for f in result["data"]["__type"]["fields"]}
|
||||
for expected in ("documents", "document", "pipelines", "pipeline", "settings", "users", "user"):
|
||||
assert expected in field_names, f"Query field '{expected}' missing from schema"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: documents queries
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
class TestDocumentsQuery:
|
||||
"""Tests for the documents and document queries."""
|
||||
|
||||
def test_list_documents_empty(self, client: TestClient):
|
||||
result = gql(client, "{ documents { id originalFilename } }")
|
||||
assert "errors" not in result
|
||||
assert result["data"]["documents"] == []
|
||||
|
||||
def test_list_documents_returns_records(self, client: TestClient, file_record: FileRecord):
|
||||
result = gql(client, "{ documents { id originalFilename mimeType fileSize } }")
|
||||
assert "errors" not in result
|
||||
docs = result["data"]["documents"]
|
||||
assert len(docs) == 1
|
||||
assert docs[0]["id"] == file_record.id
|
||||
assert docs[0]["originalFilename"] == "invoice.pdf"
|
||||
assert docs[0]["mimeType"] == "application/pdf"
|
||||
assert docs[0]["fileSize"] == 1024
|
||||
|
||||
def test_get_single_document(self, client: TestClient, file_record: FileRecord):
|
||||
result = gql(
|
||||
client,
|
||||
"query($id: Int!) { document(id: $id) { id originalFilename } }",
|
||||
variables={"id": file_record.id},
|
||||
)
|
||||
assert "errors" not in result
|
||||
assert result["data"]["document"]["id"] == file_record.id
|
||||
|
||||
def test_get_nonexistent_document_returns_null(self, client: TestClient):
|
||||
result = gql(client, "{ document(id: 99999) { id } }")
|
||||
assert "errors" not in result
|
||||
assert result["data"]["document"] is None
|
||||
|
||||
def test_documents_pagination(self, client: TestClient, db_session):
|
||||
for i in range(5):
|
||||
db_session.add(
|
||||
FileRecord(
|
||||
owner_id="user1",
|
||||
original_filename=f"doc{i}.pdf",
|
||||
local_filename=f"/workdir/tmp/doc{i}.pdf",
|
||||
file_size=100,
|
||||
filehash=f"hash{i}",
|
||||
)
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
result_page1 = gql(client, "{ documents(limit: 2, offset: 0) { id } }")
|
||||
result_page2 = gql(client, "{ documents(limit: 2, offset: 2) { id } }")
|
||||
assert "errors" not in result_page1
|
||||
assert "errors" not in result_page2
|
||||
assert len(result_page1["data"]["documents"]) == 2
|
||||
assert len(result_page2["data"]["documents"]) == 2
|
||||
|
||||
def test_documents_limit_clamped_to_100(self, client: TestClient, db_session):
|
||||
# Requesting more than 100 should be silently clamped to 100
|
||||
for i in range(5):
|
||||
db_session.add(
|
||||
FileRecord(
|
||||
owner_id="user1",
|
||||
original_filename=f"big{i}.pdf",
|
||||
local_filename=f"/workdir/tmp/big{i}.pdf",
|
||||
file_size=100,
|
||||
filehash=f"bighash{i}",
|
||||
)
|
||||
)
|
||||
db_session.commit()
|
||||
result = gql(client, "{ documents(limit: 999) { id } }")
|
||||
assert "errors" not in result
|
||||
# Just verify it doesn't error and returns something
|
||||
assert isinstance(result["data"]["documents"], list)
|
||||
|
||||
def test_documents_filter_by_owner(self, client: TestClient, db_session):
|
||||
db_session.add(
|
||||
FileRecord(
|
||||
owner_id="alice",
|
||||
original_filename="alice.pdf",
|
||||
local_filename="/workdir/tmp/alice.pdf",
|
||||
file_size=100,
|
||||
filehash="alicehash",
|
||||
)
|
||||
)
|
||||
db_session.add(
|
||||
FileRecord(
|
||||
owner_id="bob",
|
||||
original_filename="bob.pdf",
|
||||
local_filename="/workdir/tmp/bob.pdf",
|
||||
file_size=200,
|
||||
filehash="bobhash",
|
||||
)
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
result = gql(client, '{ documents(ownerId: "alice") { id originalFilename } }')
|
||||
assert "errors" not in result
|
||||
docs = result["data"]["documents"]
|
||||
assert all(d["originalFilename"] == "alice.pdf" for d in docs)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: pipelines queries
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
class TestPipelinesQuery:
|
||||
"""Tests for the pipelines and pipeline queries."""
|
||||
|
||||
def test_list_pipelines_empty(self, client: TestClient):
|
||||
result = gql(client, "{ pipelines { id name } }")
|
||||
assert "errors" not in result
|
||||
assert result["data"]["pipelines"] == []
|
||||
|
||||
def test_list_pipelines_with_steps(self, client: TestClient, pipeline_record: Pipeline):
|
||||
result = gql(
|
||||
client,
|
||||
"""
|
||||
{
|
||||
pipelines {
|
||||
id name description isDefault isActive
|
||||
steps { id stepType position enabled }
|
||||
}
|
||||
}
|
||||
""",
|
||||
)
|
||||
assert "errors" not in result
|
||||
pipelines = result["data"]["pipelines"]
|
||||
assert len(pipelines) == 1
|
||||
assert pipelines[0]["name"] == "Test Pipeline"
|
||||
assert len(pipelines[0]["steps"]) == 1
|
||||
assert pipelines[0]["steps"][0]["stepType"] == "ocr"
|
||||
|
||||
def test_get_single_pipeline(self, client: TestClient, pipeline_record: Pipeline):
|
||||
result = gql(
|
||||
client,
|
||||
"query($id: Int!) { pipeline(id: $id) { id name steps { stepType } } }",
|
||||
variables={"id": pipeline_record.id},
|
||||
)
|
||||
assert "errors" not in result
|
||||
assert result["data"]["pipeline"]["id"] == pipeline_record.id
|
||||
assert result["data"]["pipeline"]["steps"][0]["stepType"] == "ocr"
|
||||
|
||||
def test_get_nonexistent_pipeline_returns_null(self, client: TestClient):
|
||||
result = gql(client, "{ pipeline(id: 99999) { id } }")
|
||||
assert "errors" not in result
|
||||
assert result["data"]["pipeline"] is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: settings query (admin-only)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestSettingsQuery:
|
||||
"""Tests for the settings query."""
|
||||
|
||||
def test_settings_returns_data_when_no_auth(self, client: TestClient, setting_record: ApplicationSettings):
|
||||
"""When AUTH_ENABLED=False, settings are accessible (no auth required)."""
|
||||
result = gql(client, "{ settings { key value } }")
|
||||
assert "errors" not in result
|
||||
keys = [s["key"] for s in result["data"]["settings"]]
|
||||
assert "max_upload_size" in keys
|
||||
|
||||
def test_sensitive_settings_excluded(self, client: TestClient, db_session):
|
||||
"""Sensitive setting keys must never appear in the response."""
|
||||
sensitive_keys = [
|
||||
"openai_api_key",
|
||||
"session_secret",
|
||||
"azure_ai_key",
|
||||
"smtp_password",
|
||||
]
|
||||
for key in sensitive_keys:
|
||||
db_session.add(ApplicationSettings(key=key, value="super-secret"))
|
||||
db_session.commit()
|
||||
|
||||
result = gql(client, "{ settings { key value } }")
|
||||
assert "errors" not in result
|
||||
returned_keys = {s["key"] for s in result["data"]["settings"]}
|
||||
for key in sensitive_keys:
|
||||
assert key not in returned_keys, f"Sensitive key '{key}' was returned by GraphQL settings query"
|
||||
|
||||
def test_settings_auth_required_when_auth_enabled(self, client: TestClient):
|
||||
"""When AUTH_ENABLED=True and no user, settings query must return an error."""
|
||||
from app.config import settings as app_settings
|
||||
|
||||
with patch.object(app_settings, "auth_enabled", True):
|
||||
result = gql(client, "{ settings { key } }")
|
||||
# Should have errors because no user is authenticated
|
||||
assert "errors" in result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: users query (admin-only)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestUsersQuery:
|
||||
"""Tests for the users and user queries."""
|
||||
|
||||
def test_users_returns_profiles_when_no_auth(self, client: TestClient, user_profile: UserProfile):
|
||||
"""When AUTH_ENABLED=False, users are accessible."""
|
||||
result = gql(client, "{ users { userId displayName subscriptionTier } }")
|
||||
assert "errors" not in result
|
||||
users = result["data"]["users"]
|
||||
assert any(u["userId"] == "user1" for u in users)
|
||||
|
||||
def test_get_user_by_id(self, client: TestClient, user_profile: UserProfile):
|
||||
result = gql(
|
||||
client,
|
||||
'query { user(userId: "user1") { userId displayName isBlocked } }',
|
||||
)
|
||||
assert "errors" not in result
|
||||
assert result["data"]["user"]["userId"] == "user1"
|
||||
assert result["data"]["user"]["displayName"] == "Test User"
|
||||
assert result["data"]["user"]["isBlocked"] is False
|
||||
|
||||
def test_get_nonexistent_user_returns_null(self, client: TestClient):
|
||||
result = gql(client, '{ user(userId: "nobody") { userId } }')
|
||||
assert "errors" not in result
|
||||
assert result["data"]["user"] is None
|
||||
|
||||
def test_users_auth_required_when_auth_enabled(self, client: TestClient):
|
||||
"""When AUTH_ENABLED=True and no user, users query must return an error."""
|
||||
from app.config import settings as app_settings
|
||||
|
||||
with patch.object(app_settings, "auth_enabled", True):
|
||||
result = gql(client, "{ users { userId } }")
|
||||
assert "errors" in result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests: auth enforcement
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestGraphQLAuth:
|
||||
"""Verify auth is enforced for all queries when AUTH_ENABLED=True."""
|
||||
|
||||
def test_documents_auth_required_when_auth_enabled(self, client: TestClient):
|
||||
from app.config import settings as app_settings
|
||||
|
||||
with patch.object(app_settings, "auth_enabled", True):
|
||||
result = gql(client, "{ documents { id } }")
|
||||
assert "errors" in result
|
||||
|
||||
def test_pipelines_auth_required_when_auth_enabled(self, client: TestClient):
|
||||
from app.config import settings as app_settings
|
||||
|
||||
with patch.object(app_settings, "auth_enabled", True):
|
||||
result = gql(client, "{ pipelines { id } }")
|
||||
assert "errors" in result
|
||||
@@ -0,0 +1,447 @@
|
||||
"""Tests for the i18n (internationalization) and l10n (localization) utilities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import date, datetime
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.utils.i18n import (
|
||||
DEFAULT_LANGUAGE,
|
||||
SUPPORTED_LANGUAGE_CODES,
|
||||
SUPPORTED_LANGUAGES,
|
||||
_parse_accept_language,
|
||||
detect_language,
|
||||
format_date,
|
||||
format_datetime,
|
||||
format_number,
|
||||
get_language_info,
|
||||
reload_translations,
|
||||
translate,
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Translation file integrity
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestTranslationFiles:
|
||||
"""Verify that all translation JSON files are valid and complete."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clear_cache(self) -> None:
|
||||
"""Clear translation cache before each test."""
|
||||
reload_translations()
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_all_translation_files_exist(self) -> None:
|
||||
"""Every supported language must have a corresponding JSON file."""
|
||||
translations_dir = Path(__file__).resolve().parent.parent / "frontend" / "translations"
|
||||
for lang in SUPPORTED_LANGUAGES:
|
||||
filepath = translations_dir / f"{lang['code']}.json"
|
||||
assert filepath.is_file(), f"Missing translation file for {lang['code']}"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_all_translation_files_are_valid_json(self) -> None:
|
||||
"""All translation files must be parseable JSON."""
|
||||
translations_dir = Path(__file__).resolve().parent.parent / "frontend" / "translations"
|
||||
for lang in SUPPORTED_LANGUAGES:
|
||||
filepath = translations_dir / f"{lang['code']}.json"
|
||||
data = json.loads(filepath.read_text(encoding="utf-8"))
|
||||
assert isinstance(data, dict), f"{lang['code']}.json must be a dict"
|
||||
assert len(data) > 0, f"{lang['code']}.json must not be empty"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_all_languages_have_same_keys(self) -> None:
|
||||
"""All translation files should have the same set of keys as English."""
|
||||
translations_dir = Path(__file__).resolve().parent.parent / "frontend" / "translations"
|
||||
en_path = translations_dir / "en.json"
|
||||
en_keys = set(json.loads(en_path.read_text(encoding="utf-8")).keys())
|
||||
|
||||
for lang in SUPPORTED_LANGUAGES:
|
||||
if lang["code"] == "en":
|
||||
continue
|
||||
filepath = translations_dir / f"{lang['code']}.json"
|
||||
lang_keys = set(json.loads(filepath.read_text(encoding="utf-8")).keys())
|
||||
missing = en_keys - lang_keys
|
||||
assert not missing, f"{lang['code']}.json missing keys: {missing}"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Core translate() function
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestTranslate:
|
||||
"""Tests for the translate() function."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clear_cache(self) -> None:
|
||||
reload_translations()
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_english_key(self) -> None:
|
||||
"""English keys should resolve to English text."""
|
||||
result = translate("nav.dashboard", "en")
|
||||
assert result == "Dashboard"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_german_key(self) -> None:
|
||||
"""German locale should return German text."""
|
||||
result = translate("nav.dashboard", "de")
|
||||
assert result == "Übersicht"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_french_key(self) -> None:
|
||||
"""French locale should return French text."""
|
||||
result = translate("nav.dashboard", "fr")
|
||||
assert result == "Tableau de bord"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_chinese_key(self) -> None:
|
||||
"""Chinese locale should return Chinese text."""
|
||||
result = translate("nav.dashboard", "zh")
|
||||
assert result == "仪表盘"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_fallback_to_english(self) -> None:
|
||||
"""Unknown locale falls back to English."""
|
||||
result = translate("nav.dashboard", "xx")
|
||||
assert result == "Dashboard"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_missing_key_returns_key(self) -> None:
|
||||
"""Missing key falls back to the key itself."""
|
||||
result = translate("nonexistent.key", "en")
|
||||
assert result == "nonexistent.key"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_none_locale_uses_default(self) -> None:
|
||||
"""None locale defaults to English."""
|
||||
result = translate("nav.dashboard", None)
|
||||
assert result == "Dashboard"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_with_kwargs(self) -> None:
|
||||
"""Placeholders should be interpolated via kwargs."""
|
||||
result = translate("footer.copyright", "en", year="2025")
|
||||
assert result == "DocuElevate 2025"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_translate_with_kwargs_german(self) -> None:
|
||||
"""Placeholder interpolation in German."""
|
||||
result = translate("language.changed", "de", language="English")
|
||||
assert result == "Sprache geändert zu English"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Accept-Language header parsing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestParseAcceptLanguage:
|
||||
"""Tests for parsing the Accept-Language HTTP header."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_simple_language(self) -> None:
|
||||
assert _parse_accept_language("de") == "de"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_language_with_region(self) -> None:
|
||||
assert _parse_accept_language("de-DE") == "de"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_multiple_languages_quality(self) -> None:
|
||||
result = _parse_accept_language("fr;q=0.9, de;q=1.0, en;q=0.8")
|
||||
assert result == "de"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_unsupported_language_fallback(self) -> None:
|
||||
result = _parse_accept_language("ja, ko")
|
||||
assert result is None
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_empty_header(self) -> None:
|
||||
assert _parse_accept_language("") is None
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_complex_accept_language(self) -> None:
|
||||
header = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
|
||||
result = _parse_accept_language(header)
|
||||
assert result == "zh"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Language detection
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestDetectLanguage:
|
||||
"""Tests for detecting language from request context."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_session_preference_takes_priority(self) -> None:
|
||||
request = MagicMock()
|
||||
request.session = {"preferred_language": "de"}
|
||||
request.cookies = {}
|
||||
request.headers = {}
|
||||
assert detect_language(request) == "de"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_cookie_fallback(self) -> None:
|
||||
request = MagicMock()
|
||||
request.session = {}
|
||||
request.cookies = {"docuelevate_lang": "fr"}
|
||||
request.headers = {}
|
||||
assert detect_language(request) == "fr"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_accept_language_fallback(self) -> None:
|
||||
request = MagicMock()
|
||||
request.session = {}
|
||||
request.cookies = {}
|
||||
request.headers = {"accept-language": "es-ES,es;q=0.9"}
|
||||
assert detect_language(request) == "es"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_default_fallback(self) -> None:
|
||||
request = MagicMock()
|
||||
request.session = {}
|
||||
request.cookies = {}
|
||||
request.headers = {}
|
||||
assert detect_language(request) == DEFAULT_LANGUAGE
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_invalid_session_language_ignored(self) -> None:
|
||||
request = MagicMock()
|
||||
request.session = {"preferred_language": "invalid"}
|
||||
request.cookies = {"docuelevate_lang": "it"}
|
||||
request.headers = {}
|
||||
assert detect_language(request) == "it"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Localization helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestL10nFormatters:
|
||||
"""Tests for locale-aware formatting functions."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_date_english(self) -> None:
|
||||
d = date(2025, 3, 15)
|
||||
result = format_date(d, "en")
|
||||
assert "March" in result
|
||||
assert "15" in result
|
||||
assert "2025" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_date_german(self) -> None:
|
||||
d = date(2025, 3, 15)
|
||||
result = format_date(d, "de")
|
||||
assert "15." in result
|
||||
assert "2025" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_date_short(self) -> None:
|
||||
d = date(2025, 3, 15)
|
||||
result = format_date(d, "en", short=True)
|
||||
assert result == "03/15/2025"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_date_short_german(self) -> None:
|
||||
d = date(2025, 3, 15)
|
||||
result = format_date(d, "de", short=True)
|
||||
assert result == "15.03.2025"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_date_none(self) -> None:
|
||||
assert format_date(None) == ""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_datetime_none(self) -> None:
|
||||
assert format_datetime(None) == ""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_number_english(self) -> None:
|
||||
result = format_number(1234567, "en")
|
||||
assert result == "1,234,567"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_number_german(self) -> None:
|
||||
result = format_number(1234567, "de")
|
||||
assert result == "1.234.567"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_number_float_english(self) -> None:
|
||||
result = format_number(1234.56, "en")
|
||||
assert result == "1,234.56"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_number_float_german(self) -> None:
|
||||
result = format_number(1234.56, "de")
|
||||
assert result == "1.234,56"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_datetime_chinese(self) -> None:
|
||||
dt = datetime(2025, 3, 15, 14, 30)
|
||||
result = format_datetime(dt, "zh")
|
||||
assert "2025" in result
|
||||
assert "03" in result
|
||||
assert "15" in result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# get_language_info()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestGetLanguageInfo:
|
||||
"""Tests for get_language_info() utility."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_known_language(self) -> None:
|
||||
info = get_language_info("de")
|
||||
assert info is not None
|
||||
assert info["name"] == "German"
|
||||
assert info["native"] == "Deutsch"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_unknown_language(self) -> None:
|
||||
assert get_language_info("xx") is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SUPPORTED_LANGUAGES metadata
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestSupportedLanguages:
|
||||
"""Tests for language metadata constants."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_ten_languages_supported(self) -> None:
|
||||
assert len(SUPPORTED_LANGUAGES) == 31
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_supported_codes_set(self) -> None:
|
||||
expected = {
|
||||
"en",
|
||||
"de",
|
||||
"fr",
|
||||
"es",
|
||||
"it",
|
||||
"pt",
|
||||
"nl",
|
||||
"pl",
|
||||
"zh",
|
||||
"ru",
|
||||
"nb",
|
||||
"da",
|
||||
"sv",
|
||||
"fi",
|
||||
"is",
|
||||
"ga",
|
||||
"lb",
|
||||
"ca",
|
||||
"cs",
|
||||
"sk",
|
||||
"hu",
|
||||
"sl",
|
||||
"hr",
|
||||
"ro",
|
||||
"bg",
|
||||
"el",
|
||||
"et",
|
||||
"lv",
|
||||
"lt",
|
||||
"tr",
|
||||
"uk",
|
||||
}
|
||||
assert SUPPORTED_LANGUAGE_CODES == expected
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_default_language_is_english(self) -> None:
|
||||
assert DEFAULT_LANGUAGE == "en"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# API endpoint tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestI18nAPI:
|
||||
"""Tests for the i18n API endpoints."""
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_list_languages(self, client: TestClient) -> None:
|
||||
"""GET /api/i18n/languages should return all supported languages."""
|
||||
response = client.get("/api/i18n/languages")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "languages" in data
|
||||
assert len(data["languages"]) == 31
|
||||
assert data["default"] == "en"
|
||||
# Verify each language has required fields
|
||||
for lang in data["languages"]:
|
||||
assert "code" in lang
|
||||
assert "name" in lang
|
||||
assert "native" in lang
|
||||
assert "flag" in lang
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_set_language(self, client: TestClient) -> None:
|
||||
"""POST /api/i18n/language should set language preference."""
|
||||
response = client.post(
|
||||
"/api/i18n/language",
|
||||
json={"language": "de"},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["language"] == "de"
|
||||
# Verify cookie was set
|
||||
assert "docuelevate_lang" in response.cookies
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_set_language_invalid_falls_back_to_default(self, client: TestClient) -> None:
|
||||
"""Invalid language code should fall back to default."""
|
||||
response = client.post(
|
||||
"/api/i18n/language",
|
||||
json={"language": "invalid"},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["language"] == "en"
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_set_language_persists_in_cookie(self, client: TestClient) -> None:
|
||||
"""Language setting should be persisted in a cookie."""
|
||||
client.post("/api/i18n/language", json={"language": "fr"})
|
||||
# Subsequent requests should detect the language from cookie
|
||||
response = client.get("/api/i18n/languages")
|
||||
data = response.json()
|
||||
assert data["current"] == "fr"
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_base_html_uses_current_locale(self, client: TestClient) -> None:
|
||||
"""The base template should set lang attribute to current locale."""
|
||||
# Set language to German
|
||||
client.post("/api/i18n/language", json={"language": "de"})
|
||||
# Load homepage
|
||||
response = client.get("/", follow_redirects=True)
|
||||
assert response.status_code == 200
|
||||
# The lang attribute should reflect the locale
|
||||
assert 'lang="de"' in response.text or 'lang="en"' in response.text
|
||||
|
||||
@pytest.mark.integration
|
||||
def test_language_selector_in_nav(self, client: TestClient) -> None:
|
||||
"""The navigation should contain the language selector globe icon."""
|
||||
response = client.get("/", follow_redirects=True)
|
||||
if response.status_code == 200:
|
||||
assert "fa-globe" in response.text
|
||||
assert "setLanguage" in response.text
|
||||
@@ -0,0 +1,608 @@
|
||||
"""Tests to boost code coverage for all view modules below 100%.
|
||||
|
||||
Covers: api_tokens, notifications, shared_links, share, plans,
|
||||
imap_accounts, integrations, general, filemanager, files, help.
|
||||
"""
|
||||
|
||||
import os
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from app.config import settings as app_settings
|
||||
from app.database import Base, get_db
|
||||
from app.main import app
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _fresh_db():
|
||||
"""Yield a fresh in-memory SQLite session."""
|
||||
engine = create_engine(
|
||||
"sqlite:///:memory:",
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
session = sessionmaker(autocommit=False, autoflush=False, bind=engine)()
|
||||
try:
|
||||
yield session
|
||||
finally:
|
||||
session.close()
|
||||
Base.metadata.drop_all(bind=engine)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def client_fresh(_fresh_db) -> TestClient:
|
||||
"""TestClient backed by a fresh database."""
|
||||
|
||||
def _override():
|
||||
try:
|
||||
yield _fresh_db
|
||||
finally:
|
||||
pass
|
||||
|
||||
app.dependency_overrides[get_db] = _override
|
||||
with TestClient(app, base_url="http://localhost") as tc:
|
||||
yield tc
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# 1. Simple template-render views (api_tokens, notifications,
|
||||
# shared_links, share, plans)
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestApiTokensView:
|
||||
"""GET /api-tokens should render the management page."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_api_tokens_page_returns_200(self, client_fresh: TestClient):
|
||||
resp = client_fresh.get("/api-tokens")
|
||||
assert resp.status_code == 200
|
||||
assert "API Tokens" in resp.text
|
||||
|
||||
|
||||
class TestNotificationsView:
|
||||
"""GET /notifications should render the dashboard."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_notifications_page_returns_200(self, client_fresh: TestClient):
|
||||
resp = client_fresh.get("/notifications")
|
||||
assert resp.status_code == 200
|
||||
assert "Notifications" in resp.text
|
||||
|
||||
|
||||
class TestSharedLinksView:
|
||||
"""GET /shared-links should render the management page."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_shared_links_page_returns_200(self, client_fresh: TestClient):
|
||||
resp = client_fresh.get("/shared-links")
|
||||
assert resp.status_code == 200
|
||||
assert "Shared Links" in resp.text
|
||||
|
||||
|
||||
class TestShareView:
|
||||
"""GET /share/{token} should render the public share landing page."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_share_page_returns_200(self, client_fresh: TestClient):
|
||||
resp = client_fresh.get("/share/abc123")
|
||||
assert resp.status_code == 200
|
||||
# Token should be passed to the template
|
||||
assert "abc123" in resp.text
|
||||
|
||||
|
||||
class TestPlansViews:
|
||||
"""GET /admin/plans and /admin/stripe-wizard should render pages."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_plan_designer_returns_200(self, client_fresh: TestClient):
|
||||
resp = client_fresh.get("/admin/plans")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_stripe_wizard_returns_200(self, client_fresh: TestClient):
|
||||
resp = client_fresh.get("/admin/stripe-wizard")
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# 2. imap_accounts view (30.95 % → 100 %)
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestImapAccountsView:
|
||||
"""Tests for /imap-accounts view."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_imap_accounts_page_no_owner(self, client_fresh: TestClient):
|
||||
"""When no owner_id is resolved, page renders with defaults."""
|
||||
resp = client_fresh.get("/imap-accounts")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_imap_accounts_page_with_owner(self, _fresh_db, client_fresh: TestClient):
|
||||
"""When session has a user, the page queries IMAP accounts."""
|
||||
with patch("app.views.imap_accounts.get_current_owner_id", return_value="testuser"):
|
||||
with patch(
|
||||
"app.views.imap_accounts.get_user_tier_id",
|
||||
return_value="starter",
|
||||
):
|
||||
with patch(
|
||||
"app.views.imap_accounts.get_tier",
|
||||
return_value={"id": "starter", "name": "Starter", "max_mailboxes": 3},
|
||||
):
|
||||
resp = client_fresh.get("/imap-accounts")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_mailboxes_free_tier(self):
|
||||
"""Free tier should return 0 mailboxes."""
|
||||
from app.views.imap_accounts import _get_max_mailboxes
|
||||
|
||||
assert _get_max_mailboxes({"id": "free", "max_mailboxes": 0}) == 0
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_mailboxes_unlimited(self):
|
||||
"""When max_mailboxes is 0 on a non-free tier, it means unlimited."""
|
||||
from app.views.imap_accounts import _get_max_mailboxes
|
||||
|
||||
assert _get_max_mailboxes({"id": "power", "max_mailboxes": 0}) is None
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_mailboxes_limited(self):
|
||||
"""When max_mailboxes > 0, return that value."""
|
||||
from app.views.imap_accounts import _get_max_mailboxes
|
||||
|
||||
assert _get_max_mailboxes({"id": "starter", "max_mailboxes": 5}) == 5
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# 3. integrations view (82.09 % → 100 %)
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestIntegrationsView:
|
||||
"""Tests for /integrations view."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_integrations_dashboard_no_owner(self, client_fresh: TestClient):
|
||||
"""When no owner, the dashboard renders with zero-count defaults."""
|
||||
resp = client_fresh.get("/integrations")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_integrations_dashboard_with_owner(self, _fresh_db, client_fresh: TestClient):
|
||||
"""When an owner_id is resolved, DB queries run and tier is fetched."""
|
||||
with patch("app.views.integrations.get_current_owner_id", return_value="testuser"):
|
||||
with patch("app.views.integrations.get_user_tier_id", return_value="power"):
|
||||
with patch(
|
||||
"app.views.integrations.get_tier",
|
||||
return_value={
|
||||
"id": "power",
|
||||
"name": "Power",
|
||||
"max_storage_destinations": 0,
|
||||
"max_mailboxes": 0,
|
||||
},
|
||||
):
|
||||
resp = client_fresh.get("/integrations")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_integrations_dashboard_generic_exception(self, client_fresh: TestClient):
|
||||
"""A non-HTTP exception in the dashboard returns 500."""
|
||||
with patch(
|
||||
"app.views.integrations.get_current_owner_id",
|
||||
side_effect=RuntimeError("boom"),
|
||||
):
|
||||
resp = client_fresh.get("/integrations")
|
||||
assert resp.status_code == 500
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_integrations_dashboard_http_exception_passthrough(self, client_fresh: TestClient):
|
||||
"""An HTTPException inside the dashboard is re-raised, not wrapped in 500."""
|
||||
from fastapi import HTTPException
|
||||
|
||||
with patch(
|
||||
"app.views.integrations.get_current_owner_id",
|
||||
side_effect=HTTPException(status_code=403, detail="Forbidden"),
|
||||
):
|
||||
resp = client_fresh.get("/integrations")
|
||||
assert resp.status_code == 403
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_destinations_free_default(self):
|
||||
from app.views.integrations import _get_max_destinations
|
||||
|
||||
assert _get_max_destinations({"id": "free", "max_storage_destinations": 0}) == 1
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_destinations_free_with_value(self):
|
||||
from app.views.integrations import _get_max_destinations
|
||||
|
||||
assert _get_max_destinations({"id": "free", "max_storage_destinations": 3}) == 3
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_destinations_unlimited(self):
|
||||
from app.views.integrations import _get_max_destinations
|
||||
|
||||
assert _get_max_destinations({"id": "power", "max_storage_destinations": 0}) is None
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_destinations_limited(self):
|
||||
from app.views.integrations import _get_max_destinations
|
||||
|
||||
assert _get_max_destinations({"id": "starter", "max_storage_destinations": 5}) == 5
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_sources_free(self):
|
||||
from app.views.integrations import _get_max_sources
|
||||
|
||||
assert _get_max_sources({"id": "free", "max_mailboxes": 0}) == 0
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_sources_unlimited(self):
|
||||
from app.views.integrations import _get_max_sources
|
||||
|
||||
assert _get_max_sources({"id": "power", "max_mailboxes": 0}) is None
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_get_max_sources_limited(self):
|
||||
from app.views.integrations import _get_max_sources
|
||||
|
||||
assert _get_max_sources({"id": "starter", "max_mailboxes": 2}) == 2
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# 4. general view (88.68 % → 100 %)
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestGeneralViewMultiUser:
|
||||
"""Cover the multi_user_enabled subscription branch (lines 96-105)."""
|
||||
|
||||
@staticmethod
|
||||
def _signed_session(user_data: dict) -> str:
|
||||
"""Create a signed Starlette session cookie containing user_data."""
|
||||
import json
|
||||
from base64 import b64encode
|
||||
|
||||
from itsdangerous import TimestampSigner
|
||||
|
||||
secret = os.environ.get(
|
||||
"SESSION_SECRET",
|
||||
"test_secret_key_for_testing_must_be_at_least_32_characters_long",
|
||||
)
|
||||
signer = TimestampSigner(secret)
|
||||
data = {"user": user_data}
|
||||
return signer.sign(b64encode(json.dumps(data).encode("utf-8"))).decode("utf-8")
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_home_page_multi_user_with_subscription(self, _fresh_db, client_fresh: TestClient):
|
||||
"""When multi_user_enabled is True and user has owner_id, subscription info is fetched.
|
||||
|
||||
Lines 96-103: Exercises the subscription lookup path.
|
||||
"""
|
||||
cookie_val = self._signed_session({"username": "testuser", "email": "test@example.com", "is_admin": False})
|
||||
tier_mock = {
|
||||
"id": "starter",
|
||||
"name": "Starter",
|
||||
"lifetime_file_limit": 1000,
|
||||
"daily_upload_limit": 50,
|
||||
"monthly_upload_limit": 500,
|
||||
}
|
||||
usage_mock = {"lifetime": 10, "today": 2, "month": 8}
|
||||
with (
|
||||
patch.object(app_settings, "multi_user_enabled", True),
|
||||
patch("app.utils.setup_wizard.is_setup_required", return_value=False),
|
||||
patch("app.views.general.get_provider_status", return_value={}),
|
||||
patch("app.views.general.validate_storage_configs", return_value={}),
|
||||
patch("app.utils.subscription.get_user_tier_id", return_value="starter"),
|
||||
patch("app.utils.subscription.get_tier", return_value=tier_mock),
|
||||
patch("app.utils.subscription.get_user_usage", return_value=usage_mock),
|
||||
):
|
||||
client_fresh.cookies.set("session", cookie_val)
|
||||
resp = client_fresh.get("/?setup=complete")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_home_page_multi_user_subscription_error(self, _fresh_db, client_fresh: TestClient):
|
||||
"""When subscription lookup fails, error is logged but page still renders.
|
||||
|
||||
Lines 104-105: Exercises the exception handling branch.
|
||||
"""
|
||||
cookie_val = self._signed_session({"username": "testuser", "email": "test@example.com", "is_admin": False})
|
||||
with (
|
||||
patch.object(app_settings, "multi_user_enabled", True),
|
||||
patch("app.utils.setup_wizard.is_setup_required", return_value=False),
|
||||
patch("app.views.general.get_provider_status", return_value={}),
|
||||
patch("app.views.general.validate_storage_configs", return_value={}),
|
||||
patch("app.utils.subscription.get_user_tier_id", side_effect=RuntimeError("boom")),
|
||||
):
|
||||
client_fresh.cookies.set("session", cookie_val)
|
||||
resp = client_fresh.get("/?setup=complete")
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# 5. filemanager view (96.63 % → 100 %)
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestFilemanagerCoverageGaps:
|
||||
"""Cover the remaining gaps in filemanager.py."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_size_petabytes(self):
|
||||
"""Line 43: _format_size should return PB for very large sizes."""
|
||||
from app.views.filemanager import _format_size
|
||||
|
||||
# 1 PB = 1024^5 bytes
|
||||
one_pb = 1024**5
|
||||
result = _format_size(one_pb)
|
||||
assert "PB" in result
|
||||
assert "1.0 PB" == result
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_format_size_multiple_petabytes(self):
|
||||
"""Large values above 1 PB."""
|
||||
from app.views.filemanager import _format_size
|
||||
|
||||
result = _format_size(5 * 1024**5)
|
||||
assert "PB" in result
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_scan_dir_with_broken_symlink(self, tmp_path):
|
||||
"""Lines 104-106: files that cannot be stat'd are skipped with a warning.
|
||||
|
||||
Using a broken symlink to trigger OSError on stat().
|
||||
"""
|
||||
from app.views.filemanager import _scan_dir
|
||||
|
||||
# Create a broken symlink — stat() will raise FileNotFoundError (subclass of OSError)
|
||||
broken_link = tmp_path / "broken_link.txt"
|
||||
broken_link.symlink_to("/nonexistent/target/file")
|
||||
|
||||
# Also create a valid file so we can verify it's included
|
||||
valid_file = tmp_path / "valid.txt"
|
||||
valid_file.write_text("hello")
|
||||
|
||||
db_paths: set[str] = set()
|
||||
entries = _scan_dir(tmp_path, tmp_path, db_paths)
|
||||
|
||||
# The broken symlink should be skipped, the valid file should be included
|
||||
entry_names = [e["name"] for e in entries]
|
||||
assert "broken_link.txt" not in entry_names
|
||||
assert "valid.txt" in entry_names
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_scan_dir_oserror(self, tmp_path):
|
||||
"""OSError during stat in _scan_dir is caught and file is skipped.
|
||||
|
||||
We create a second broken symlink for this test.
|
||||
"""
|
||||
from app.views.filemanager import _scan_dir
|
||||
|
||||
broken_link = tmp_path / "also_broken.txt"
|
||||
broken_link.symlink_to("/another/nonexistent/path")
|
||||
|
||||
valid_file = tmp_path / "good.txt"
|
||||
valid_file.write_text("ok")
|
||||
db_paths: set[str] = set()
|
||||
|
||||
entries = _scan_dir(tmp_path, tmp_path, db_paths)
|
||||
entry_names = [e["name"] for e in entries]
|
||||
assert "also_broken.txt" not in entry_names
|
||||
assert "good.txt" in entry_names
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_walk_all_files_with_broken_symlink(self, tmp_path):
|
||||
"""Lines 146-147: files that fail stat during walk are skipped.
|
||||
|
||||
Using a broken symlink to trigger OSError.
|
||||
"""
|
||||
from app.views.filemanager import _walk_all_files
|
||||
|
||||
broken_link = tmp_path / "broken.pdf"
|
||||
broken_link.symlink_to("/nonexistent/target/file")
|
||||
|
||||
valid_file = tmp_path / "valid.pdf"
|
||||
valid_file.write_text("content")
|
||||
|
||||
db_paths: set[str] = set()
|
||||
entries = _walk_all_files(tmp_path, db_paths)
|
||||
|
||||
entry_names = [e["name"] for e in entries]
|
||||
assert "broken.pdf" not in entry_names
|
||||
assert "valid.pdf" in entry_names
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# 6. files view (99.21 % → 100 %)
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestFilesViewCoverageGaps:
|
||||
"""Cover the remaining branches in files.py."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_compute_processing_flow_with_pipeline_steps(self):
|
||||
"""Lines 504-515: pipeline_steps filtering in _compute_processing_flow."""
|
||||
from app.views.files import _compute_processing_flow
|
||||
|
||||
# Create mock pipeline steps
|
||||
ps1 = SimpleNamespace(enabled=True, step_type="ocr")
|
||||
ps2 = SimpleNamespace(enabled=False, step_type="extract_metadata")
|
||||
ps3 = SimpleNamespace(enabled=True, step_type="send_to_destinations")
|
||||
|
||||
# Create mock logs with all required attributes including task_id
|
||||
log1 = SimpleNamespace(
|
||||
step_name="create_file_record",
|
||||
status="completed",
|
||||
message="ok",
|
||||
timestamp=None,
|
||||
started_at=None,
|
||||
completed_at=None,
|
||||
task_id="task-001",
|
||||
)
|
||||
log2 = SimpleNamespace(
|
||||
step_name="check_text",
|
||||
status="completed",
|
||||
message="ok",
|
||||
timestamp=None,
|
||||
started_at=None,
|
||||
completed_at=None,
|
||||
task_id="task-002",
|
||||
)
|
||||
|
||||
result = _compute_processing_flow([log1, log2], pipeline_steps=[ps1, ps2, ps3])
|
||||
|
||||
# _compute_processing_flow returns a list of stage dicts
|
||||
stage_keys = [s["key"] for s in result]
|
||||
assert "create_file_record" in stage_keys # always shown
|
||||
assert "check_text" in stage_keys # OCR step type + ran
|
||||
# extract_metadata is disabled, so its stages should NOT be included
|
||||
assert "extract_metadata_with_gpt" not in stage_keys
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_compute_processing_flow_with_pipeline_steps_none(self):
|
||||
"""When pipeline_steps is None, all stages are shown."""
|
||||
from app.views.files import _compute_processing_flow
|
||||
|
||||
result = _compute_processing_flow([], pipeline_steps=None)
|
||||
stage_keys = [s["key"] for s in result]
|
||||
assert "create_file_record" in stage_keys
|
||||
assert "extract_metadata_with_gpt" in stage_keys
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_compute_processing_flow_with_empty_pipeline_steps(self):
|
||||
"""When pipeline_steps is empty list, only always-show + ran stages remain."""
|
||||
from app.views.files import _compute_processing_flow
|
||||
|
||||
result = _compute_processing_flow([], pipeline_steps=[])
|
||||
stage_keys = [s["key"] for s in result]
|
||||
assert "create_file_record" in stage_keys
|
||||
# Other stages should be filtered out
|
||||
assert "convert_to_pdf" not in stage_keys
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_compute_processing_flow_dedup_enabled(self):
|
||||
"""When dedup is enabled and shown, check_for_duplicates stage appears."""
|
||||
from app.views.files import _compute_processing_flow
|
||||
|
||||
with (
|
||||
patch.object(app_settings, "enable_deduplication", True),
|
||||
patch.object(app_settings, "show_deduplication_step", True),
|
||||
):
|
||||
result = _compute_processing_flow([], pipeline_steps=None)
|
||||
stage_keys = [s["key"] for s in result]
|
||||
assert "check_for_duplicates" in stage_keys
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_file_detail_safe_exists_value_error(self, _fresh_db, client_fresh: TestClient):
|
||||
"""Test that _safe_exists handles ValueError from commonpath gracefully.
|
||||
|
||||
Lines 240-241: When os.path.commonpath raises ValueError (e.g., paths
|
||||
on different drives on Windows), _safe_exists returns False.
|
||||
"""
|
||||
from app.models import FileRecord
|
||||
|
||||
# Create a file record with all required fields
|
||||
rec = FileRecord(
|
||||
original_filename="test.pdf",
|
||||
local_filename="/tmp/test_local.pdf",
|
||||
original_file_path="/tmp/test_original.pdf",
|
||||
processed_file_path="/tmp/test_processed.pdf",
|
||||
file_size=100,
|
||||
mime_type="application/pdf",
|
||||
filehash="abc123def456",
|
||||
)
|
||||
_fresh_db.add(rec)
|
||||
_fresh_db.commit()
|
||||
_fresh_db.refresh(rec)
|
||||
|
||||
# Patch commonpath to raise ValueError
|
||||
with patch("os.path.commonpath", side_effect=ValueError("different drives")):
|
||||
resp = client_fresh.get(f"/files/{rec.id}")
|
||||
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# 7. help view (96 % → 100 %)
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestHelpViewCoverageGaps:
|
||||
"""Cover the missing branch in help.py (34->37)."""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_help_page_no_session_attr(self, client_fresh: TestClient):
|
||||
"""When no session user is set, defaults are used for Zammad widgets."""
|
||||
resp = client_fresh.get("/help")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
async def test_help_page_request_without_session(self):
|
||||
"""Direct function call where request has no session attribute.
|
||||
|
||||
Branch 34->37: when hasattr(request, 'session') is False.
|
||||
"""
|
||||
from app.views.help import help_center
|
||||
|
||||
# Create a mock request without session attribute
|
||||
mock_request = MagicMock(spec=[]) # spec=[] means no attributes
|
||||
# help_center checks hasattr(request, "session")
|
||||
# With spec=[], hasattr will return False
|
||||
|
||||
with patch("app.views.help.templates") as mock_templates:
|
||||
mock_templates.TemplateResponse.return_value = "ok"
|
||||
await help_center(mock_request)
|
||||
|
||||
# Template should be called with empty user context
|
||||
call_args = mock_templates.TemplateResponse.call_args
|
||||
ctx = call_args[0][1] if len(call_args[0]) > 1 else call_args[1].get("context", {})
|
||||
assert ctx["user_name"] == ""
|
||||
assert ctx["user_email"] == ""
|
||||
assert ctx["user_id"] == ""
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_help_page_with_logged_in_user(self, client_fresh: TestClient):
|
||||
"""When session has user data, Zammad widget fields are populated.
|
||||
|
||||
Covers lines 41-43 (user_name, user_email, user_id extraction).
|
||||
"""
|
||||
import json
|
||||
from base64 import b64encode
|
||||
|
||||
from itsdangerous import TimestampSigner
|
||||
|
||||
secret = os.environ.get(
|
||||
"SESSION_SECRET",
|
||||
"test_secret_key_for_testing_must_be_at_least_32_characters_long",
|
||||
)
|
||||
signer = TimestampSigner(secret)
|
||||
session_data = {
|
||||
"user": {
|
||||
"name": "Jane Doe",
|
||||
"email": "jane@example.com",
|
||||
"preferred_username": "janedoe",
|
||||
}
|
||||
}
|
||||
cookie_val = signer.sign(b64encode(json.dumps(session_data).encode("utf-8"))).decode("utf-8")
|
||||
client_fresh.cookies.set("session", cookie_val)
|
||||
|
||||
resp = client_fresh.get("/help")
|
||||
assert resp.status_code == 200
|
||||
Reference in New Issue
Block a user