Add notifications crate shared between API and indexer to send Telegram messages on scan/thumbnail/conversion completion/failure, metadata linking, batch and refresh events. Configurable via a new Notifications tab in the backoffice settings with per-event toggle switches grouped by category. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
722 lines
33 KiB
TypeScript
722 lines
33 KiB
TypeScript
import type { TranslationKey } from "./fr";
|
||
|
||
const en: Record<TranslationKey, string> = {
|
||
// Navigation
|
||
"nav.dashboard": "Dashboard",
|
||
"nav.books": "Books",
|
||
"nav.series": "Series",
|
||
"nav.libraries": "Libraries",
|
||
"nav.jobs": "Jobs",
|
||
"nav.tokens": "Tokens",
|
||
"nav.settings": "Settings",
|
||
"nav.navigation": "Navigation",
|
||
"nav.closeMenu": "Close menu",
|
||
"nav.openMenu": "Open menu",
|
||
|
||
// Common
|
||
"common.save": "Save",
|
||
"common.saving": "Saving...",
|
||
"common.cancel": "Cancel",
|
||
"common.close": "Close",
|
||
"common.delete": "Delete",
|
||
"common.edit": "Edit",
|
||
"common.search": "Search",
|
||
"common.clear": "Clear",
|
||
"common.view": "View",
|
||
"common.all": "All",
|
||
"common.enabled": "Enabled",
|
||
"common.disabled": "Disabled",
|
||
"common.browse": "Browse",
|
||
"common.add": "Add",
|
||
"common.noData": "No data",
|
||
"common.loading": "Loading...",
|
||
"common.error": "Error",
|
||
"common.networkError": "Network error",
|
||
"common.show": "Show",
|
||
"common.perPage": "per page",
|
||
"common.next": "Next",
|
||
"common.previous": "Previous",
|
||
"common.first": "First",
|
||
"common.previousPage": "Previous page",
|
||
"common.nextPage": "Next page",
|
||
"common.backoffice": "backoffice",
|
||
"common.and": "and",
|
||
"common.via": "via",
|
||
|
||
// Reading status
|
||
"status.unread": "Unread",
|
||
"status.reading": "Reading",
|
||
"status.read": "Read",
|
||
|
||
// Series status
|
||
"seriesStatus.ongoing": "Ongoing",
|
||
"seriesStatus.ended": "Ended",
|
||
"seriesStatus.hiatus": "Hiatus",
|
||
"seriesStatus.cancelled": "Cancelled",
|
||
"seriesStatus.upcoming": "Upcoming",
|
||
"seriesStatus.allStatuses": "All statuses",
|
||
"seriesStatus.notDefined": "Not defined",
|
||
|
||
// Dashboard
|
||
"dashboard.title": "Dashboard",
|
||
"dashboard.subtitle": "Overview of your comic book collection. Manage your libraries, track your reading progress and explore your books and series.",
|
||
"dashboard.loadError": "Unable to load statistics. Check that the API is running.",
|
||
"dashboard.books": "Books",
|
||
"dashboard.series": "Series",
|
||
"dashboard.libraries": "Libraries",
|
||
"dashboard.pages": "Pages",
|
||
"dashboard.authors": "Authors",
|
||
"dashboard.totalSize": "Total size",
|
||
"dashboard.readingStatus": "Reading status",
|
||
"dashboard.byFormat": "By format",
|
||
"dashboard.byLibrary": "By library",
|
||
"dashboard.booksAdded": "Books added (last 12 months)",
|
||
"dashboard.popularSeries": "Popular series",
|
||
"dashboard.noSeries": "No series yet",
|
||
"dashboard.unknown": "Unknown",
|
||
"dashboard.readCount": "{{read}}/{{total}} read",
|
||
"dashboard.metadataCoverage": "Metadata coverage",
|
||
"dashboard.seriesLinked": "Linked series",
|
||
"dashboard.seriesUnlinked": "Unlinked series",
|
||
"dashboard.byProvider": "By provider",
|
||
"dashboard.bookMetadata": "Book metadata",
|
||
"dashboard.withSummary": "With summary",
|
||
"dashboard.withIsbn": "With ISBN",
|
||
|
||
// Books page
|
||
"books.title": "Books",
|
||
"books.searchPlaceholder": "Search by title, author, series...",
|
||
"books.library": "Library",
|
||
"books.allLibraries": "All libraries",
|
||
"books.status": "Status",
|
||
"books.sort": "Sort",
|
||
"books.sortTitle": "Title",
|
||
"books.sortLatest": "Latest added",
|
||
"books.resultCount": "{{count}} result{{plural}}",
|
||
"books.resultCountFor": "{{count}} result{{plural}} for \"{{query}}\"",
|
||
"books.bookCount": "{{count}} book{{plural}}",
|
||
"books.seriesHeading": "Series",
|
||
"books.unclassified": "Unclassified",
|
||
"books.noResults": "No books found for \"{{query}}\"",
|
||
"books.noBooks": "No books available",
|
||
"books.coverOf": "Cover of {{name}}",
|
||
"books.format": "Format",
|
||
"books.allFormats": "All formats",
|
||
|
||
// Series page
|
||
"series.title": "Series",
|
||
"series.searchPlaceholder": "Search by series name...",
|
||
"series.reading": "Reading",
|
||
"series.missing": "Missing",
|
||
"series.missingBooks": "Missing books",
|
||
"series.matchingQuery": "matching",
|
||
"series.noResults": "No series found matching your filters",
|
||
"series.noSeries": "No series available",
|
||
"series.missingCount": "{{count}} missing",
|
||
"series.readCount": "{{read}}/{{total}} read",
|
||
|
||
// Authors page
|
||
"nav.authors": "Authors",
|
||
"authors.title": "Authors",
|
||
"authors.searchPlaceholder": "Search by author name...",
|
||
"authors.bookCount": "{{count}} book{{plural}}",
|
||
"authors.seriesCount": "{{count}} serie{{plural}}",
|
||
"authors.noResults": "No authors found matching your filters",
|
||
"authors.noAuthors": "No authors available",
|
||
"authors.matchingQuery": "matching",
|
||
"authors.sortName": "Name",
|
||
"authors.sortBooks": "Book count",
|
||
"authors.booksBy": "Books by {{name}}",
|
||
"authors.seriesBy": "Series by {{name}}",
|
||
|
||
// Libraries page
|
||
"libraries.title": "Libraries",
|
||
"libraries.addLibrary": "Add a library",
|
||
"libraries.addLibraryDescription": "Create a new library from an existing folder",
|
||
"libraries.disabled": "Disabled",
|
||
"libraries.books": "Books",
|
||
"libraries.series": "Series",
|
||
"libraries.auto": "Auto",
|
||
"libraries.manual": "Manual",
|
||
"libraries.nextScan": "Next: {{time}}",
|
||
"libraries.imminent": "Imminent",
|
||
"libraries.nextMetadataRefresh": "Next metadata refresh: {{time}}",
|
||
"libraries.nextMetadataRefreshShort": "Meta.: {{time}}",
|
||
"libraries.scanLabel": "Scan: {{mode}}",
|
||
"libraries.watcherLabel": "File watch",
|
||
"libraries.metaRefreshLabel": "Meta refresh: {{mode}}",
|
||
"libraries.index": "Index",
|
||
"libraries.fullIndex": "Full",
|
||
"libraries.batchMetadata": "Batch metadata",
|
||
"libraries.libraryName": "Library name",
|
||
"libraries.addButton": "Add library",
|
||
|
||
// Library sub-pages
|
||
"libraryBooks.allBooks": "All books",
|
||
"libraryBooks.booksOfSeries": "Books from \"{{series}}\"",
|
||
"libraryBooks.filterLabel": "Books from series \"{{series}}\"",
|
||
"libraryBooks.viewAll": "View all books",
|
||
"libraryBooks.noBooks": "No books in this library",
|
||
"libraryBooks.noBooksInSeries": "No books in series \"{{series}}\"",
|
||
"librarySeries.noSeries": "No series found in this library",
|
||
"librarySeries.noBooksInSeries": "No books in this series",
|
||
|
||
// Library actions
|
||
"libraryActions.settingsTitle": "Library settings",
|
||
"libraryActions.sectionIndexation": "Indexation",
|
||
"libraryActions.sectionMetadata": "Metadata",
|
||
"libraryActions.autoScan": "Scheduled scan",
|
||
"libraryActions.autoScanDesc": "Automatically scan for new and modified files",
|
||
"libraryActions.fileWatch": "Real-time file watch",
|
||
"libraryActions.fileWatchDesc": "Detect file changes instantly via filesystem events",
|
||
"libraryActions.schedule": "Frequency",
|
||
"libraryActions.provider": "Provider",
|
||
"libraryActions.providerDesc": "Source used to fetch series and volume metadata",
|
||
"libraryActions.fallback": "Fallback provider",
|
||
"libraryActions.fallbackDesc": "Used when the primary provider returns no results",
|
||
"libraryActions.default": "Default",
|
||
"libraryActions.none": "None",
|
||
"libraryActions.metadataRefreshSchedule": "Auto-refresh",
|
||
"libraryActions.metadataRefreshDesc": "Periodically re-fetch metadata for existing series",
|
||
"libraryActions.saving": "Saving...",
|
||
|
||
// Library sub-page header
|
||
"libraryHeader.libraries": "Libraries",
|
||
"libraryHeader.bookCount": "{{count}} book{{plural}}",
|
||
"libraryHeader.enabled": "Enabled",
|
||
|
||
// Monitoring
|
||
"monitoring.auto": "Auto",
|
||
"monitoring.manual": "Manual",
|
||
"monitoring.hourly": "Hourly",
|
||
"monitoring.daily": "Daily",
|
||
"monitoring.weekly": "Weekly",
|
||
"monitoring.fileWatch": "Real-time file watching",
|
||
|
||
// Jobs page
|
||
"jobs.title": "Indexing jobs",
|
||
"jobs.startJob": "Start a job",
|
||
"jobs.startJobDescription": "Select a library (or all) and choose the action to perform.",
|
||
"jobs.allLibraries": "All libraries",
|
||
"jobs.rebuild": "Rebuild",
|
||
"jobs.rescan": "Deep rescan",
|
||
"jobs.fullRebuild": "Full rebuild",
|
||
"jobs.generateThumbnails": "Generate thumbnails",
|
||
"jobs.regenerateThumbnails": "Regenerate thumbnails",
|
||
"jobs.batchMetadata": "Batch metadata",
|
||
"jobs.refreshMetadata": "Refresh metadata",
|
||
"jobs.refreshMetadataDescription": "Refreshes metadata for all series already linked to an external provider. Re-downloads information from the provider and updates series and books in the database (respecting locked fields). Series without an approved link are ignored. <strong>Requires a specific library</strong> (does not work on \"All libraries\").",
|
||
"jobs.referenceTitle": "Job types reference",
|
||
"jobs.groupIndexation": "Indexation",
|
||
"jobs.groupThumbnails": "Thumbnails",
|
||
"jobs.groupMetadata": "Metadata",
|
||
"jobs.requiresLibrary": "Requires a specific library",
|
||
"jobs.rebuildShort": "Scan new & modified files",
|
||
"jobs.rescanShort": "Re-walk all directories to discover new formats",
|
||
"jobs.fullRebuildShort": "Delete all & re-scan from scratch",
|
||
"jobs.generateThumbnailsShort": "Missing thumbnails only",
|
||
"jobs.regenerateThumbnailsShort": "Recreate all thumbnails",
|
||
"jobs.batchMetadataShort": "Auto-match unlinked series",
|
||
"jobs.refreshMetadataShort": "Update existing linked series",
|
||
"jobs.rebuildDescription": "Incremental scan: detects files added, modified, or deleted since the last scan, indexes them, and generates missing thumbnails. Existing unmodified data is preserved. This is the most common and fastest action.",
|
||
"jobs.rescanDescription": "Re-walks all directories regardless of whether they changed, discovering files in newly supported formats (e.g. EPUB). Existing books and metadata are fully preserved — only genuinely new files are added. Slower than a rebuild but safe for your data.",
|
||
"jobs.fullRebuildDescription": "Deletes all indexed data (books, series, thumbnails) then performs a full scan from scratch. Useful if the database is out of sync or corrupted. Long and destructive operation: reading statuses and manual metadata will be lost.",
|
||
"jobs.generateThumbnailsDescription": "Generates thumbnails only for books that don't have one yet. Existing thumbnails are not affected. Useful after an import or if some thumbnails are missing.",
|
||
"jobs.regenerateThumbnailsDescription": "Regenerates all thumbnails from scratch, replacing existing ones. Useful if thumbnail quality or size has changed in the configuration, or if thumbnails are corrupted.",
|
||
"jobs.batchMetadataDescription": "Automatically searches metadata for each series in the library from the configured provider (with fallback if configured). Only results with a unique 100% confidence match are applied automatically. Already linked series are skipped. A detailed per-series report is available at the end of the job. <strong>Requires a specific library</strong> (does not work on \"All libraries\").",
|
||
|
||
// Jobs list
|
||
"jobsList.id": "ID",
|
||
"jobsList.library": "Library",
|
||
"jobsList.type": "Type",
|
||
"jobsList.status": "Status",
|
||
"jobsList.stats": "Stats",
|
||
"jobsList.duration": "Duration",
|
||
"jobsList.created": "Created",
|
||
"jobsList.actions": "Actions",
|
||
|
||
// Job row
|
||
"jobRow.showProgress": "Show progress",
|
||
"jobRow.hideProgress": "Hide progress",
|
||
"jobRow.scanned": "{{count}} scanned",
|
||
"jobRow.filesIndexed": "{{count}} files indexed",
|
||
"jobRow.filesRemoved": "{{count}} files removed",
|
||
"jobRow.thumbnailsGenerated": "{{count}} thumbnails generated",
|
||
"jobRow.metadataProcessed": "{{count}} series processed",
|
||
"jobRow.metadataRefreshed": "{{count}} series refreshed",
|
||
"jobRow.errors": "{{count}} errors",
|
||
"jobRow.view": "View",
|
||
|
||
// Job progress
|
||
"jobProgress.loadingProgress": "Loading progress...",
|
||
"jobProgress.sseError": "Failed to parse SSE data",
|
||
"jobProgress.connectionLost": "Connection lost",
|
||
"jobProgress.error": "Error: {{message}}",
|
||
"jobProgress.done": "Done",
|
||
"jobProgress.currentFile": "Current: {{file}}",
|
||
"jobProgress.pages": "pages",
|
||
"jobProgress.thumbnails": "thumbnails",
|
||
"jobProgress.filesUnit": "files",
|
||
"jobProgress.scanned": "Scanned: {{count}}",
|
||
"jobProgress.indexed": "Indexed: {{count}}",
|
||
"jobProgress.removed": "Removed: {{count}}",
|
||
"jobProgress.errors": "Errors: {{count}}",
|
||
|
||
// Job detail
|
||
"jobDetail.backToJobs": "Back to jobs",
|
||
"jobDetail.title": "Job details",
|
||
"jobDetail.completedIn": "Completed in {{duration}}",
|
||
"jobDetail.failedAfter": "after {{duration}}",
|
||
"jobDetail.jobFailed": "Job failed",
|
||
"jobDetail.cancelled": "Cancelled",
|
||
"jobDetail.overview": "Overview",
|
||
"jobDetail.timeline": "Timeline",
|
||
"jobDetail.created": "Created",
|
||
"jobDetail.started": "Started",
|
||
"jobDetail.pendingStart": "Pending start…",
|
||
"jobDetail.finished": "Finished",
|
||
"jobDetail.failed": "Failed",
|
||
"jobDetail.library": "Library",
|
||
"jobDetail.book": "Book",
|
||
"jobDetail.allLibraries": "All libraries",
|
||
"jobDetail.phase1": "Phase 1 — Discovery",
|
||
"jobDetail.phase2a": "Phase 2a — Page extraction",
|
||
"jobDetail.phase2b": "Phase 2b — Thumbnail generation",
|
||
"jobDetail.metadataSearch": "Metadata search",
|
||
"jobDetail.metadataSearchDesc": "Searching external providers for each series",
|
||
"jobDetail.metadataRefresh": "Metadata refresh",
|
||
"jobDetail.metadataRefreshDesc": "Re-downloading metadata from providers for already linked series",
|
||
"jobDetail.refreshReport": "Refresh report",
|
||
"jobDetail.refreshReportDesc": "{{count}} linked series processed",
|
||
"jobDetail.refreshed": "Refreshed",
|
||
"jobDetail.unchanged": "Unchanged",
|
||
"jobDetail.refreshChanges": "Changes detail",
|
||
"jobDetail.refreshChangesDesc": "{{count}} series with changes",
|
||
"jobDetail.phase1Desc": "Scanning and indexing library files",
|
||
"jobDetail.phase2aDesc": "Extracting the first page of each archive (page count + raw image)",
|
||
"jobDetail.phase2bDesc": "Generating thumbnails for scanned books",
|
||
"jobDetail.inProgress": "in progress",
|
||
"jobDetail.duration": "Duration: {{duration}}",
|
||
"jobDetail.currentFile": "Current file",
|
||
"jobDetail.generated": "Generated",
|
||
"jobDetail.processed": "Processed",
|
||
"jobDetail.total": "Total",
|
||
"jobDetail.remaining": "Remaining",
|
||
"jobDetail.indexStats": "Index statistics",
|
||
"jobDetail.scanned": "Scanned",
|
||
"jobDetail.indexed": "Indexed",
|
||
"jobDetail.removed": "Removed",
|
||
"jobDetail.warnings": "Warnings",
|
||
"jobDetail.errors": "Errors",
|
||
"jobDetail.thumbnailStats": "Thumbnail statistics",
|
||
"jobDetail.batchReport": "Batch report",
|
||
"jobDetail.seriesAnalyzed": "{{count}} series analyzed",
|
||
"jobDetail.autoMatched": "Auto-matched",
|
||
"jobDetail.alreadyLinked": "Already linked",
|
||
"jobDetail.noResults": "No results",
|
||
"jobDetail.tooManyResults": "Too many results",
|
||
"jobDetail.lowConfidence": "Low confidence",
|
||
"jobDetail.resultsBySeries": "Results by series",
|
||
"jobDetail.seriesProcessed": "{{count}} series processed",
|
||
"jobDetail.candidates": "candidate{{plural}}",
|
||
"jobDetail.confidence": "confidence",
|
||
"jobDetail.match": "Match: {{title}}",
|
||
"jobDetail.fileErrors": "File errors ({{count}})",
|
||
"jobDetail.fileErrorsDesc": "Errors encountered while processing files",
|
||
|
||
// Job types
|
||
"jobType.rebuild": "Indexing",
|
||
"jobType.rescan": "Deep rescan",
|
||
"jobType.full_rebuild": "Full indexing",
|
||
"jobType.thumbnail_rebuild": "Thumbnails",
|
||
"jobType.thumbnail_regenerate": "Regen. thumbnails",
|
||
"jobType.cbr_to_cbz": "CBR → CBZ",
|
||
"jobType.metadata_batch": "Batch metadata",
|
||
"jobType.metadata_refresh": "Refresh meta.",
|
||
"jobType.rebuildLabel": "Incremental indexing",
|
||
"jobType.rebuildDesc": "Scans new/modified files, analyzes them, and generates missing thumbnails.",
|
||
"jobType.rescanLabel": "Deep rescan",
|
||
"jobType.rescanDesc": "Re-walks all directories to discover files in newly supported formats (e.g. EPUB). Existing data is preserved — only new files are added.",
|
||
"jobType.full_rebuildLabel": "Full reindexing",
|
||
"jobType.full_rebuildDesc": "Deletes all existing data then performs a full scan, re-analysis, and thumbnail generation.",
|
||
"jobType.thumbnail_rebuildLabel": "Thumbnail rebuild",
|
||
"jobType.thumbnail_rebuildDesc": "Generates thumbnails only for books that don't have one. Existing thumbnails are preserved.",
|
||
"jobType.thumbnail_regenerateLabel": "Thumbnail regeneration",
|
||
"jobType.thumbnail_regenerateDesc": "Regenerates all thumbnails from scratch, replacing existing ones.",
|
||
"jobType.cbr_to_cbzLabel": "CBR → CBZ conversion",
|
||
"jobType.cbr_to_cbzDesc": "Converts a CBR archive to the open CBZ format.",
|
||
"jobType.metadata_batchLabel": "Batch metadata",
|
||
"jobType.metadata_batchDesc": "Searches external metadata providers for all series in the library and automatically applies 100% confidence matches.",
|
||
"jobType.metadata_refreshLabel": "Metadata refresh",
|
||
"jobType.metadata_refreshDesc": "Re-downloads and updates metadata for all series already linked to an external provider.",
|
||
|
||
// Status badges
|
||
"statusBadge.extracting_pages": "Extracting pages",
|
||
"statusBadge.generating_thumbnails": "Thumbnails",
|
||
|
||
// Jobs indicator
|
||
"jobsIndicator.viewAll": "View all jobs",
|
||
"jobsIndicator.activeTasks": "Active jobs",
|
||
"jobsIndicator.runningAndPending": "{{running}} running, {{pending}} pending",
|
||
"jobsIndicator.pendingTasks": "{{count}} pending job{{plural}}",
|
||
"jobsIndicator.overallProgress": "Overall progress",
|
||
"jobsIndicator.viewAllLink": "View all →",
|
||
"jobsIndicator.noActiveTasks": "No active jobs",
|
||
"jobsIndicator.autoRefresh": "Auto-refresh every 2s",
|
||
"jobsIndicator.taskCount": "{{count}} active job{{plural}}",
|
||
"jobsIndicator.thumbnails": "Thumbnails",
|
||
"jobsIndicator.regeneration": "Regeneration",
|
||
|
||
// Time
|
||
"time.justNow": "Just now",
|
||
"time.minutesAgo": "{{count}}m ago",
|
||
"time.hoursAgo": "{{count}}h ago",
|
||
|
||
// Tokens page
|
||
"tokens.title": "API Tokens",
|
||
"tokens.created": "Token created",
|
||
"tokens.createdDescription": "Copy it now, it won't be shown again",
|
||
"tokens.createNew": "Create a new token",
|
||
"tokens.createDescription": "Generate a new API token with the desired scope",
|
||
"tokens.tokenName": "Token name",
|
||
"tokens.scopeRead": "Read",
|
||
"tokens.scopeAdmin": "Admin",
|
||
"tokens.createButton": "Create token",
|
||
"tokens.name": "Name",
|
||
"tokens.scope": "Scope",
|
||
"tokens.prefix": "Prefix",
|
||
"tokens.status": "Status",
|
||
"tokens.actions": "Actions",
|
||
"tokens.revoked": "Revoked",
|
||
"tokens.active": "Active",
|
||
"tokens.revoke": "Revoke",
|
||
|
||
// Settings page
|
||
"settings.title": "Settings",
|
||
"settings.general": "General",
|
||
"settings.integrations": "Integrations",
|
||
"settings.savedSuccess": "Settings saved successfully",
|
||
"settings.savedError": "Failed to save settings",
|
||
"settings.saveError": "Error saving settings",
|
||
"settings.cacheClearError": "Failed to clear cache",
|
||
|
||
// Settings - Image Processing
|
||
"settings.imageProcessing": "Image processing",
|
||
"settings.imageProcessingDesc": "These settings only apply when a client explicitly requests a format conversion via the API (e.g. <code>?format=webp&width=800</code>). Pages served without parameters are delivered as-is from the archive, without processing.",
|
||
"settings.defaultFormat": "Default output format",
|
||
"settings.defaultQuality": "Default quality (1-100)",
|
||
"settings.defaultFilter": "Default resize filter",
|
||
"settings.filterLanczos": "Lanczos3 (Best quality)",
|
||
"settings.filterTriangle": "Triangle (Faster)",
|
||
"settings.filterNearest": "Nearest (Fastest)",
|
||
"settings.maxWidth": "Maximum allowed width (px)",
|
||
|
||
// Settings - Cache
|
||
"settings.cache": "Cache",
|
||
"settings.cacheDesc": "Manage image cache and storage",
|
||
"settings.cacheSize": "Cache size",
|
||
"settings.files": "Files",
|
||
"settings.directory": "Directory",
|
||
"settings.cacheDirectory": "Cache directory",
|
||
"settings.maxSizeMb": "Max size (MB)",
|
||
"settings.clearing": "Clearing...",
|
||
"settings.clearCache": "Clear cache",
|
||
|
||
// Settings - Performance
|
||
"settings.performanceLimits": "Performance limits",
|
||
"settings.performanceDesc": "Configure API performance, rate limiting, and thumbnail generation concurrency",
|
||
"settings.concurrentRenders": "Concurrent renders",
|
||
"settings.concurrentRendersHelp": "Maximum number of parallel page renders and thumbnail generations",
|
||
"settings.timeoutSeconds": "Timeout (seconds)",
|
||
"settings.rateLimit": "Rate limit (req/s)",
|
||
"settings.limitsNote": "Note: Changes to limits require a server restart to take effect. The \"Concurrent renders\" setting controls both page rendering and thumbnail generation parallelism.",
|
||
|
||
// Settings - Thumbnails
|
||
"settings.thumbnails": "Thumbnails",
|
||
"settings.thumbnailsDesc": "Configure thumbnail generation during indexing",
|
||
"settings.enableThumbnails": "Enable thumbnails",
|
||
"settings.outputFormat": "Output format",
|
||
"settings.formatOriginal": "Original (No re-encoding)",
|
||
"settings.formatOriginalDesc": "Resizes to target dimensions, keeps the source format (JPEG→JPEG). Much faster generation.",
|
||
"settings.formatReencodeDesc": "Resizes and re-encodes to the selected format.",
|
||
"settings.width": "Width (px)",
|
||
"settings.height": "Height (px)",
|
||
"settings.quality": "Quality (1-100)",
|
||
"settings.thumbnailDirectory": "Thumbnail directory",
|
||
"settings.totalSize": "Total size",
|
||
"settings.thumbnailsNote": "Note: Thumbnail settings are used during indexing. Existing thumbnails will not be automatically regenerated. Thumbnail generation concurrency is controlled by the \"Concurrent renders\" setting in Performance limits above.",
|
||
|
||
// Settings - Komga
|
||
"settings.komgaSync": "Komga sync",
|
||
"settings.komgaDesc": "Import reading status from a Komga server. Books are matched by title (case-insensitive). Credentials are not stored.",
|
||
"settings.komgaUrl": "Komga URL",
|
||
"settings.username": "Username",
|
||
"settings.password": "Password",
|
||
"settings.syncing": "Syncing...",
|
||
"settings.syncReadBooks": "Sync read books",
|
||
"settings.komgaRead": "Read on Komga",
|
||
"settings.matched": "Matched",
|
||
"settings.alreadyRead": "Already read",
|
||
"settings.newlyMarked": "Newly marked",
|
||
"settings.matchedBooks": "{{count}} matched book{{plural}}",
|
||
"settings.unmatchedBooks": "{{count}} unmatched book{{plural}}",
|
||
"settings.syncHistory": "Sync history",
|
||
"settings.read": "read",
|
||
"settings.new": "new",
|
||
"settings.unmatched": "unmatched",
|
||
|
||
// Settings - Metadata Providers
|
||
"settings.metadataProviders": "Metadata providers",
|
||
"settings.metadataProvidersDesc": "Configure external metadata providers for series/book enrichment. Each library can override the default provider. All providers are available for quick search in the metadata modal.",
|
||
"settings.defaultProvider": "Default provider",
|
||
"settings.defaultProviderHelp": "Used by default for metadata search. Libraries can override it individually.",
|
||
"settings.metadataLanguage": "Metadata language",
|
||
"settings.metadataLanguageHelp": "Preferred language for search results and descriptions. Fallback: English.",
|
||
"settings.apiKeys": "API keys",
|
||
"settings.googleBooksKey": "Google Books API key",
|
||
"settings.googleBooksPlaceholder": "Optional — for higher rate limits",
|
||
"settings.googleBooksHelp": "Works without a key but with lower rate limits.",
|
||
"settings.comicvineKey": "ComicVine API key",
|
||
"settings.comicvinePlaceholder": "Required to use ComicVine",
|
||
"settings.comicvineHelp": "Get your key at",
|
||
"settings.freeProviders": "are free and do not require an API key.",
|
||
|
||
// Settings - Status Mappings
|
||
"settings.statusMappings": "Status mappings",
|
||
"settings.statusMappingsDesc": "Configure the mapping between provider statuses and database statuses. Multiple provider statuses can map to a single target status.",
|
||
"settings.targetStatus": "Target status",
|
||
"settings.providerStatuses": "Provider statuses",
|
||
"settings.addProviderStatus": "Add a provider status…",
|
||
"settings.noMappings": "No mappings configured",
|
||
"settings.unmappedSection": "Unmapped",
|
||
"settings.addMapping": "Add a mapping",
|
||
"settings.selectTargetStatus": "Select a target status",
|
||
"settings.newTargetPlaceholder": "New target status (e.g. hiatus)",
|
||
"settings.createTargetStatus": "Create status",
|
||
|
||
// Settings - Prowlarr
|
||
"settings.prowlarr": "Prowlarr",
|
||
"settings.prowlarrDesc": "Configure Prowlarr to search for releases on indexers (torrents/usenet). Only manual search is available for now.",
|
||
"settings.prowlarrUrl": "Prowlarr URL",
|
||
"settings.prowlarrUrlPlaceholder": "http://localhost:9696",
|
||
"settings.prowlarrApiKey": "API Key",
|
||
"settings.prowlarrApiKeyPlaceholder": "Prowlarr API key",
|
||
"settings.prowlarrCategories": "Categories",
|
||
"settings.prowlarrCategoriesHelp": "Comma-separated Newznab category IDs (7030 = Comics, 7020 = Ebooks)",
|
||
"settings.testConnection": "Test connection",
|
||
"settings.testing": "Testing...",
|
||
"settings.testSuccess": "Connection successful",
|
||
"settings.testFailed": "Connection failed",
|
||
|
||
// Prowlarr search modal
|
||
"prowlarr.searchButton": "Prowlarr",
|
||
"prowlarr.modalTitle": "Prowlarr Search",
|
||
"prowlarr.searchSeries": "Search series",
|
||
"prowlarr.searchVolume": "Search",
|
||
"prowlarr.searching": "Searching...",
|
||
"prowlarr.noResults": "No results found",
|
||
"prowlarr.resultCount": "{{count}} result{{plural}}",
|
||
"prowlarr.missingVolumes": "Missing volumes",
|
||
"prowlarr.columnTitle": "Title",
|
||
"prowlarr.columnIndexer": "Indexer",
|
||
"prowlarr.columnSize": "Size",
|
||
"prowlarr.columnSeeders": "Seeds",
|
||
"prowlarr.columnLeechers": "Peers",
|
||
"prowlarr.columnProtocol": "Protocol",
|
||
"prowlarr.searchPlaceholder": "Edit search query...",
|
||
"prowlarr.searchAction": "Search",
|
||
"prowlarr.searchError": "Search failed",
|
||
"prowlarr.notConfigured": "Prowlarr is not configured",
|
||
"prowlarr.download": "Download",
|
||
"prowlarr.info": "Info",
|
||
"prowlarr.sendToQbittorrent": "Send to qBittorrent",
|
||
"prowlarr.sending": "Sending...",
|
||
"prowlarr.sentSuccess": "Sent to qBittorrent",
|
||
"prowlarr.sentError": "Failed to send to qBittorrent",
|
||
"prowlarr.missingVol": "Vol. {{vol}} missing",
|
||
|
||
// Settings - qBittorrent
|
||
"settings.qbittorrent": "qBittorrent",
|
||
"settings.qbittorrentDesc": "Configure qBittorrent as a download client. Torrents found via Prowlarr can be sent directly to qBittorrent.",
|
||
"settings.qbittorrentUrl": "qBittorrent URL",
|
||
"settings.qbittorrentUrlPlaceholder": "http://localhost:8080",
|
||
"settings.qbittorrentUsername": "Username",
|
||
"settings.qbittorrentPassword": "Password",
|
||
|
||
// Settings - Telegram Notifications
|
||
"settings.notifications": "Notifications",
|
||
"settings.telegram": "Telegram",
|
||
"settings.telegramDesc": "Receive Telegram notifications for scans, errors, and metadata linking.",
|
||
"settings.botToken": "Bot Token",
|
||
"settings.botTokenPlaceholder": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
|
||
"settings.chatId": "Chat ID",
|
||
"settings.chatIdPlaceholder": "123456789",
|
||
"settings.telegramEnabled": "Enable Telegram notifications",
|
||
"settings.telegramEvents": "Events",
|
||
"settings.eventCategoryScan": "Scans",
|
||
"settings.eventCategoryThumbnail": "Thumbnails",
|
||
"settings.eventCategoryConversion": "CBR → CBZ Conversion",
|
||
"settings.eventCategoryMetadata": "Metadata",
|
||
"settings.eventCompleted": "Completed",
|
||
"settings.eventFailed": "Failed",
|
||
"settings.eventCancelled": "Cancelled",
|
||
"settings.eventLinked": "Linked",
|
||
"settings.eventBatchCompleted": "Batch completed",
|
||
"settings.eventBatchFailed": "Batch failed",
|
||
"settings.eventRefreshCompleted": "Refresh completed",
|
||
"settings.eventRefreshFailed": "Refresh failed",
|
||
"settings.telegramHelp": "How to get the required information?",
|
||
"settings.telegramHelpBot": "Open Telegram, search for <b>@BotFather</b>, send <code>/newbot</code> and follow the instructions. Copy the token it gives you.",
|
||
"settings.telegramHelpChat": "Send a message to your bot, then open <code>https://api.telegram.org/bot<TOKEN>/getUpdates</code> in your browser. The <b>chat id</b> is in <code>message.chat.id</code>.",
|
||
"settings.telegramHelpGroup": "For a group: add the bot to the group, send a message, then check the same URL. Group IDs are negative (e.g. <code>-123456789</code>).",
|
||
|
||
// Settings - Language
|
||
"settings.language": "Language",
|
||
"settings.languageDesc": "Choose the interface language",
|
||
|
||
// Pagination
|
||
"pagination.show": "Show",
|
||
"pagination.displaying": "Displaying {{count}} items",
|
||
"pagination.range": "{{start}}-{{end}} of {{total}}",
|
||
|
||
// Book detail
|
||
"bookDetail.libraries": "Libraries",
|
||
"bookDetail.coverOf": "Cover of {{title}}",
|
||
"bookDetail.technicalInfo": "Technical information",
|
||
"bookDetail.file": "File",
|
||
"bookDetail.fileFormat": "File format",
|
||
"bookDetail.parsing": "Parsing",
|
||
"bookDetail.updatedAt": "Updated",
|
||
|
||
// Book preview
|
||
"bookPreview.preview": "Preview",
|
||
"bookPreview.pages": "pages {{start}}–{{end}} / {{total}}",
|
||
"bookPreview.prev": "← Prev",
|
||
"bookPreview.next": "Next →",
|
||
|
||
// Edit book form
|
||
"editBook.editMetadata": "Edit metadata",
|
||
"editBook.title": "Title",
|
||
"editBook.titlePlaceholder": "Book title",
|
||
"editBook.authors": "Author(s)",
|
||
"editBook.addAuthor": "Add an author (Enter to confirm)",
|
||
"editBook.language": "Language",
|
||
"editBook.languagePlaceholder": "e.g. fr, en, jp",
|
||
"editBook.series": "Series",
|
||
"editBook.seriesPlaceholder": "Series name",
|
||
"editBook.volume": "Volume",
|
||
"editBook.volumePlaceholder": "Volume number",
|
||
"editBook.isbn": "ISBN",
|
||
"editBook.publishDate": "Publish date",
|
||
"editBook.publishDatePlaceholder": "e.g. 2023-01-15",
|
||
"editBook.description": "Description",
|
||
"editBook.descriptionPlaceholder": "Summary / book description",
|
||
"editBook.lockedField": "Locked field (protected from syncs)",
|
||
"editBook.clickToLock": "Click to lock this field",
|
||
"editBook.lockedFieldsNote": "Locked fields will not be overwritten by external metadata syncs.",
|
||
"editBook.saveError": "Error saving",
|
||
"editBook.savingLabel": "Saving…",
|
||
"editBook.saveLabel": "Save",
|
||
"editBook.removeAuthor": "Remove {{name}}",
|
||
|
||
// Edit series form
|
||
"editSeries.title": "Edit series",
|
||
"editSeries.name": "Name",
|
||
"editSeries.namePlaceholder": "Series name",
|
||
"editSeries.startYear": "Start year",
|
||
"editSeries.startYearPlaceholder": "e.g. 1990",
|
||
"editSeries.totalVolumes": "Number of volumes",
|
||
"editSeries.status": "Status",
|
||
"editSeries.authors": "Author(s)",
|
||
"editSeries.applyToBooks": "→ books",
|
||
"editSeries.applyToBooksTitle": "Apply author and language to all books in the series",
|
||
"editSeries.bookAuthor": "Author (books)",
|
||
"editSeries.bookAuthorPlaceholder": "Overwrites the author field of each book",
|
||
"editSeries.bookLanguage": "Language (books)",
|
||
"editSeries.publishers": "Publisher(s)",
|
||
"editSeries.addPublisher": "Add a publisher (Enter to confirm)",
|
||
"editSeries.descriptionPlaceholder": "Synopsis or series description…",
|
||
|
||
// Convert button
|
||
"convert.convertToCbz": "Convert to CBZ",
|
||
"convert.converting": "Converting…",
|
||
"convert.started": "Conversion started.",
|
||
"convert.viewJob": "View job →",
|
||
"convert.failed": "Conversion failed",
|
||
"convert.unknownError": "Unknown error",
|
||
|
||
// Mark read buttons
|
||
"markRead.markUnread": "Mark unread",
|
||
"markRead.markAllRead": "Mark all read",
|
||
"markRead.markAsRead": "Mark as read",
|
||
|
||
// Metadata search modal
|
||
"metadata.metadataLink": "Metadata link",
|
||
"metadata.searchExternal": "Search external metadata",
|
||
"metadata.provider": "Provider:",
|
||
"metadata.searching": "Searching \"{{name}}\"...",
|
||
"metadata.noResults": "No results found.",
|
||
"metadata.resultCount": "{{count}} result{{plural}} found",
|
||
"metadata.howToSync": "How would you like to sync?",
|
||
"metadata.syncSeriesOnly": "Sync series only",
|
||
"metadata.syncSeriesOnlyDesc": "Update description, authors, publishers, and year",
|
||
"metadata.syncSeriesAndBooks": "Sync series + books",
|
||
"metadata.syncSeriesAndBooksDesc": "Also fetch the book list and show missing volumes",
|
||
"metadata.backToResults": "Back to results",
|
||
"metadata.syncingMetadata": "Syncing metadata...",
|
||
"metadata.syncSuccess": "Metadata synced successfully!",
|
||
"metadata.seriesLabel": "Series",
|
||
"metadata.booksLabel": "Books",
|
||
"metadata.booksMatched": "{{matched}} matched",
|
||
"metadata.booksUnmatched": "{{count}} unmatched",
|
||
"metadata.external": "External",
|
||
"metadata.local": "Local",
|
||
"metadata.missingLabel": "Missing",
|
||
"metadata.missingBooks": "{{count}} missing book{{plural}}",
|
||
"metadata.unknown": "Unknown",
|
||
"metadata.linkedTo": "Linked to",
|
||
"metadata.viewExternal": "View on external source",
|
||
"metadata.searchAgain": "Search again",
|
||
"metadata.unlink": "Unlink",
|
||
"metadata.searchButton": "Search metadata",
|
||
"metadata.metadataButton": "Metadata",
|
||
"metadata.locked": "locked",
|
||
"metadata.searchFailed": "Search failed",
|
||
"metadata.linkFailed": "Link creation failed",
|
||
"metadata.approveFailed": "Approval failed",
|
||
"metadata.chapters": "chapters",
|
||
"metadata.volumes": "volumes",
|
||
"metadata.inProgress": "in progress",
|
||
"metadata.fallbackUsed": "(fallback)",
|
||
|
||
// Field labels
|
||
"field.description": "Description",
|
||
"field.authors": "Authors",
|
||
"field.publishers": "Publishers",
|
||
"field.start_year": "Year",
|
||
"field.total_volumes": "Volumes",
|
||
"field.status": "Status",
|
||
"field.summary": "Summary",
|
||
"field.isbn": "ISBN",
|
||
"field.publish_date": "Publish date",
|
||
"field.language": "Language",
|
||
|
||
// Folder picker/browser
|
||
"folder.selectFolder": "Select a folder...",
|
||
"folder.selectFolderTitle": "Select folder",
|
||
"folder.clickToSelect": "Click a folder to select it",
|
||
"folder.noFolders": "No folders found",
|
||
|
||
// Series filters
|
||
"seriesFilters.all": "All",
|
||
"seriesFilters.missingBooks": "Missing books",
|
||
|
||
// Metadata filter
|
||
"series.metadata": "Metadata",
|
||
"series.metadataAll": "All",
|
||
"series.metadataLinked": "Linked",
|
||
"series.metadataUnlinked": "Not linked",
|
||
};
|
||
|
||
export default en;
|