Rename all OPDS-prefixed models to generic names (Server, Feed, Entry, Link, StreamLink), expand the ServerSoftware interface to cover all server interactions, and implement a full Kavita REST API client that replaces the OPDS delegation. - Rename OPDS* models to generic names across ~60 files - Add database migrations 13 (opds_id → entry_id) and 14 (unify credentials) - Create OPDSServerSoftware wrapping existing OPDS services - Create KavitaApiClient for direct Kavita REST API calls - Create KavitaFeedMapper to convert Kavita JSON to Feed/Entry models - Rewrite KavitaServerSoftware to use native API (no OPDS delegation) - Unify server credentials (remove softwareUsername/softwarePassword) - Simplify add/edit server UI to single auth section - Add test connection button to server add/edit screens - Add progress indicator to PublicationCard using local and server data - Eliminate softwareType branching in reader screens - Add EntryProgress and fetchEntryProgress to ServerSoftware interface - Fix Entry.acquisitionLink crash on empty links - Add 59 new tests covering models, services, and providers
537 lines
18 KiB
Text
537 lines
18 KiB
Text
{
|
|
"@@locale": "en",
|
|
|
|
"appName": "Worldhopper",
|
|
|
|
"navLibrary": "Library",
|
|
"navServers": "Servers",
|
|
"navSettings": "Settings",
|
|
|
|
"settingsTitle": "Settings",
|
|
"settingsAppearance": "Appearance",
|
|
"settingsAppearanceSubtitle": "Display options",
|
|
"settingsLanguage": "Language",
|
|
"settingsLanguageSubtitle": "App language",
|
|
"settingsReaders": "Readers",
|
|
"settingsReadersSubtitle": "Reader options",
|
|
"settingsAdvanced": "Advanced",
|
|
"settingsAdvancedSubtitle": "Developer and debugging",
|
|
"settingsAbout": "About",
|
|
"settingsAboutSubtitle": "Worldhopper",
|
|
|
|
"appearanceTitle": "Appearance",
|
|
"appearanceTheme": "Theme",
|
|
"themeLight": "Light",
|
|
"themeDark": "Dark",
|
|
"themeSystem": "System",
|
|
"themeSystemSubtitle": "Follow device theme",
|
|
|
|
"languageTitle": "Language",
|
|
"languageSystem": "System default",
|
|
"languageSystemSubtitle": "Use device language",
|
|
|
|
"readersTitle": "Readers",
|
|
"readersGeneralSection": "General",
|
|
"readersEinkMode": "E-ink mode",
|
|
"readersEinkModeSubtitle": "Disable animations for e-ink displays",
|
|
"readersImageReaderSection": "Image Reader",
|
|
"readersCachingSection": "Caching",
|
|
"readersReadingDirection": "Reading direction",
|
|
"readersFilterQuality": "Filter quality",
|
|
"readersPrecachePages": "Pre-cache pages",
|
|
"readersTwoPageSpread": "Two-page spread",
|
|
"readersTwoPageSpreadSubtitle": "Show two pages side by side on wide screens",
|
|
"readersFirstPageIsCover": "First page is cover",
|
|
"readersFirstPageIsCoverSubtitle": "Show the first page alone in two-page spread",
|
|
"readersSyncProgress": "Sync progress for cached pages",
|
|
"readersSyncProgressSubtitle": "Re-fetches each page on turn so the server tracks your reading progress. Uses additional data.",
|
|
|
|
"readingDirectionTitle": "Reading Direction",
|
|
"readingModeLtr": "Left to right",
|
|
"readingModeLtrDescription": "Standard Western reading order",
|
|
"readingModeRtl": "Right to left",
|
|
"readingModeRtlDescription": "Manga-style reading order",
|
|
"readingModeVertical": "Vertical scroll",
|
|
"readingModeVerticalDescription": "Continuous webtoon-style scrolling",
|
|
"readingDirectionHelp": "Controls the reading direction for the image reader. Left to right is standard for Western comics, right to left for manga, and vertical scroll for webtoons.",
|
|
"readingModeShortLtr": "LTR",
|
|
"readingModeShortRtl": "RTL",
|
|
"readingModeShortVertical": "Vertical",
|
|
|
|
"filterQualityTitle": "Filter Quality",
|
|
"filterQualityNone": "None",
|
|
"filterQualityNoneDescription": "Fastest, may look pixelated",
|
|
"filterQualityLow": "Low",
|
|
"filterQualityLowDescription": "Bilinear interpolation",
|
|
"filterQualityMedium": "Medium",
|
|
"filterQualityMediumDescription": "Bilinear with mipmaps, good balance",
|
|
"filterQualityHigh": "High",
|
|
"filterQualityHighDescription": "Bicubic interpolation, best quality",
|
|
"filterQualityHelp": "Controls how images are scaled when a page is zoomed out to fit the screen. Higher quality makes text and fine details sharper but uses more GPU resources. Medium is recommended for most devices.",
|
|
|
|
"precachePagesTitle": "Pre-cache Pages",
|
|
"precachePagesOff": "Off",
|
|
"precachePagesOffDescription": "Pages load on demand",
|
|
"precachePages1": "1 page",
|
|
"precachePages1Description": "Minimal pre-loading",
|
|
"precachePages2": "2 pages",
|
|
"precachePages2Description": "Light pre-loading",
|
|
"precachePages3": "3 pages",
|
|
"precachePages3Description": "Balanced, recommended",
|
|
"precachePages4": "4 pages",
|
|
"precachePages4Description": "Aggressive pre-loading",
|
|
"precachePages5": "5 pages",
|
|
"precachePages5Description": "Maximum pre-loading, uses more bandwidth",
|
|
"precachePagesHelp": "Controls how many upcoming pages are pre-loaded in the background while reading. Higher values make swiping feel more seamless but use more bandwidth and memory.\n\nNote: Pre-fetching pages may mark them as read on the server. Your local reading progress will not be affected.",
|
|
|
|
"advancedTitle": "Advanced",
|
|
"advancedDeveloperMode": "Developer mode",
|
|
"advancedDeveloperModeSubtitle": "Enable debugging tools",
|
|
"advancedTests": "Tests",
|
|
"advancedTestsSubtitle": "Preview UI components",
|
|
"advancedDebuggingInfo": "Debugging info",
|
|
"advancedVersion": "Version",
|
|
"advancedBuildNumber": "Build number",
|
|
"advancedPackageName": "Package name",
|
|
"advancedDatabaseVersion": "Database version",
|
|
"advancedPlatform": "Platform",
|
|
"advancedCopyToClipboard": "Copy to clipboard",
|
|
"advancedCopyToClipboardSubtitle": "Copy all debug info for bug reports",
|
|
"advancedDebugInfoCopied": "Debug info copied to clipboard",
|
|
"advancedFailedToLoadInfo": "Failed to load info",
|
|
|
|
"aboutTitle": "About",
|
|
"aboutVersion": "Version",
|
|
"aboutVersionUnknown": "unknown",
|
|
"aboutSourceCode": "Source code",
|
|
"aboutReportIssue": "Report an issue",
|
|
"aboutReportIssueSubtitle": "Open an issue on the repository",
|
|
|
|
"devTestsTitle": "Dev Tests",
|
|
"devTestsSnackBars": "Snack Bars",
|
|
"devTestsSuccess": "Success",
|
|
"devTestsError": "Error",
|
|
"devTestsWarning": "Warning",
|
|
"devTestsInfo": "Info",
|
|
"devTestsSuccessMessage": "This is a success message",
|
|
"devTestsErrorMessage": "This is an error message",
|
|
"devTestsWarningMessage": "This is a warning message",
|
|
"devTestsInfoMessage": "This is an info message",
|
|
|
|
"serverListTitle": "My Servers",
|
|
"serverListEmpty": "No Servers Yet",
|
|
"serverListEmptySubtitle": "Add your first OPDS server to start browsing and reading",
|
|
"serverListOffline": "You are offline. Connect to the internet to browse servers.",
|
|
"serverListErrorLoading": "Error loading servers: {error}",
|
|
"@serverListErrorLoading": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"serverListRetry": "Retry",
|
|
"serverListAddServer": "Add Server",
|
|
"serverDeleteTitle": "Delete Server",
|
|
"serverDeleteConfirmation": "Are you sure you want to delete \"{name}\"?",
|
|
"@serverDeleteConfirmation": {
|
|
"placeholders": {
|
|
"name": { "type": "String" }
|
|
}
|
|
},
|
|
"serverDeleted": "{name} deleted",
|
|
"@serverDeleted": {
|
|
"placeholders": {
|
|
"name": { "type": "String" }
|
|
}
|
|
},
|
|
|
|
"addServerTitle": "Add Server",
|
|
"addServerNameLabel": "Server Name",
|
|
"addServerNameHint": "My Library",
|
|
"addServerUrlLabel": "Server URL",
|
|
"addServerUrlHint": "https://example.com/opds",
|
|
"addServerUrlHintKavita": "https://kavita.example.com",
|
|
"addServerServerType": "Server Type",
|
|
"addServerServerTypeSubtitle": "Auto-detected from URL. Change if needed.",
|
|
"serverTypeGeneric": "Generic OPDS",
|
|
"serverTypeKavita": "Kavita",
|
|
"addServerAuth": "Authentication",
|
|
"addServerAuthSubtitle": "Credentials for server access",
|
|
"addServerRequiresAuth": "Requires Authentication",
|
|
"addServerRequiresAuthSubtitle": "Enable if server requires login",
|
|
"addServerUsername": "Username",
|
|
"addServerPassword": "Password",
|
|
"addServerValidationNameRequired": "Please enter a server name",
|
|
"addServerValidationUrlRequired": "Please enter a server URL",
|
|
"addServerValidationUrlInvalid": "Please enter a valid URL",
|
|
"addServerValidationUrlScheme": "URL must start with http:// or https://",
|
|
"addServerValidationUsernameRequired": "Please enter a username",
|
|
"addServerValidationPasswordRequired": "Please enter a password",
|
|
"addServerHelp": "Enter the root URL of your OPDS server. Credentials will be securely stored on your device.",
|
|
"testConnectionButton": "Test Connection",
|
|
"testConnectionTesting": "Testing...",
|
|
"testConnectionSuccess": "Connection successful!",
|
|
"testConnectionError": "Connection failed: {error}",
|
|
"@testConnectionError": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"addServerButton": "Add Server",
|
|
"addServerDuplicate": "A server with this URL already exists",
|
|
"addServerSuccess": "{name} added successfully",
|
|
"@addServerSuccess": {
|
|
"placeholders": {
|
|
"name": { "type": "String" }
|
|
}
|
|
},
|
|
"addServerError": "Error adding server: {error}",
|
|
"@addServerError": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
|
|
"editServerTitle": "Edit Server",
|
|
"editServerNotFound": "Server not found",
|
|
"editServerInfo": "Server Information",
|
|
"editServerAdded": "Added",
|
|
"editServerLastSynced": "Last Synced",
|
|
"editServerSaveButton": "Save Changes",
|
|
"editServerSuccess": "{name} updated successfully",
|
|
"@editServerSuccess": {
|
|
"placeholders": {
|
|
"name": { "type": "String" }
|
|
}
|
|
},
|
|
"editServerError": "Error updating server: {error}",
|
|
"@editServerError": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"editServerErrorLoading": "Error loading server: {error}",
|
|
"@editServerErrorLoading": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
|
|
"readerError": "Error",
|
|
"readerNoStreamLink": "This publication cannot be read (no stream link)",
|
|
"readerServerNotFound": "Server not found",
|
|
"readerErrorLoadingServer": "Error loading server: {error}",
|
|
"@readerErrorLoadingServer": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"readerReadingDirectionWithMode": "Reading direction ({mode})",
|
|
"@readerReadingDirectionWithMode": {
|
|
"placeholders": {
|
|
"mode": { "type": "String" }
|
|
}
|
|
},
|
|
"readerPageOf": "Page {current} of {total}",
|
|
"@readerPageOf": {
|
|
"placeholders": {
|
|
"current": { "type": "int" },
|
|
"total": { "type": "int" }
|
|
}
|
|
},
|
|
"readerPagesOf": "Pages {start}-{end} of {total}",
|
|
"@readerPagesOf": {
|
|
"placeholders": {
|
|
"start": { "type": "int" },
|
|
"end": { "type": "int" },
|
|
"total": { "type": "int" }
|
|
}
|
|
},
|
|
|
|
"epubPreparing": "Preparing...",
|
|
"epubLoadingFromCache": "Loading from cache...",
|
|
"epubDownloading": "Downloading... {percent}%",
|
|
"@epubDownloading": {
|
|
"placeholders": {
|
|
"percent": { "type": "int" }
|
|
}
|
|
},
|
|
"epubProcessing": "Processing EPUB...",
|
|
"epubOpeningReader": "Opening reader...",
|
|
"epubErrorLoading": "Error loading EPUB: {error}",
|
|
"@epubErrorLoading": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"epubGoBack": "Go Back",
|
|
"epubSearch": "Search",
|
|
"epubSearchHint": "Enter search term...",
|
|
"epubNoResults": "No results found",
|
|
"epubSearchResults": "{count} results for \"{query}\"",
|
|
"@epubSearchResults": {
|
|
"placeholders": {
|
|
"count": { "type": "int" },
|
|
"query": { "type": "String" }
|
|
}
|
|
},
|
|
"epubSearchFailed": "Search failed: {error}",
|
|
"@epubSearchFailed": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"epubChapters": "Chapters",
|
|
"epubBack": "Back",
|
|
"epubSettings": "Settings",
|
|
"epubFontSize": "Font Size",
|
|
"epubFontSizeReset": "Reset",
|
|
|
|
"libraryTitle": "Library",
|
|
"libraryRecentlyRead": "Recently Read",
|
|
"libraryNoServers": "No Servers Configured",
|
|
"libraryNoServersSubtitle": "Add an OPDS server to start reading books",
|
|
"libraryAddServer": "Add Server",
|
|
"libraryNoHistory": "No Reading History",
|
|
"libraryNoHistorySubtitle": "Start reading a book to see it here",
|
|
"libraryBrowseServers": "Browse Servers",
|
|
"libraryErrorLoading": "Error Loading Library",
|
|
|
|
"browserLoading": "Loading...",
|
|
"browserLibrary": "Library",
|
|
"browserNoContent": "No Content Available",
|
|
"browserLibraryEmpty": "This library appears to be empty",
|
|
"browserCollectionEmpty": "This collection appears to be empty",
|
|
"browserFailedToLoadLibrary": "Failed to Load Library",
|
|
"browserFailedToLoadFeed": "Failed to Load Feed",
|
|
"browserRetry": "Retry",
|
|
"browserFailedToLoadMore": "Failed to load more: {error}",
|
|
"@browserFailedToLoadMore": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"browserOfflineEpubNotCached": "This EPUB is not cached. You may not be able to read it offline.",
|
|
"browserOfflinePagesWarning": "You are offline. Pages may not load properly.",
|
|
|
|
"publicationPages": "{count} pages",
|
|
"@publicationPages": {
|
|
"placeholders": {
|
|
"count": { "type": "int" }
|
|
}
|
|
},
|
|
"publicationReadingProgress": "Reading Progress",
|
|
"publicationPageOfTotal": "Page {current} of {total}",
|
|
"@publicationPageOfTotal": {
|
|
"placeholders": {
|
|
"current": { "type": "int" },
|
|
"total": { "type": "int" }
|
|
}
|
|
},
|
|
"publicationLastRead": "Last read: {time}",
|
|
"@publicationLastRead": {
|
|
"placeholders": {
|
|
"time": { "type": "String" }
|
|
}
|
|
},
|
|
"publicationCannotRead": "This publication cannot be read in the app",
|
|
"publicationContinueFromPage": "Continue reading from page {page}",
|
|
"@publicationContinueFromPage": {
|
|
"placeholders": {
|
|
"page": { "type": "int" }
|
|
}
|
|
},
|
|
"publicationStartReading": "Start Reading",
|
|
"publicationContinueReading": "Continue Reading",
|
|
"publicationReadAgain": "Read Again",
|
|
"publicationStartFromBeginning": "Start from Beginning",
|
|
"publicationCollection": "Collection",
|
|
|
|
"recentlyReadPublicationNotFound": "Publication not found",
|
|
"recentlyReadErrorLoading": "Error loading publication",
|
|
"recentlyReadViewRawData": "View raw data",
|
|
"recentlyReadRemove": "Remove from Recently Read",
|
|
"recentlyReadRemoveTitle": "Remove from Recently Read",
|
|
"recentlyReadRemoveConfirmation": "Remove \"{title}\" from your reading history?\n\nThis will not delete the book from your library.",
|
|
"@recentlyReadRemoveConfirmation": {
|
|
"placeholders": {
|
|
"title": { "type": "String" }
|
|
}
|
|
},
|
|
"recentlyReadRemoved": "Removed from Recently Read",
|
|
"recentlyReadRemoveFailed": "Failed to remove: {error}",
|
|
"@recentlyReadRemoveFailed": {
|
|
"placeholders": {
|
|
"error": { "type": "String" }
|
|
}
|
|
},
|
|
"recentlyReadRawData": "Raw Data",
|
|
"recentlyReadOfflineEpubNotCached": "This EPUB is not cached. Connect to internet to download.",
|
|
"recentlyReadOfflinePagesWarning": "You are offline. Pages may not load.",
|
|
"recentlyReadUnsupportedFormat": "Unsupported format",
|
|
|
|
"serverCardEdit": "Edit",
|
|
"serverCardDelete": "Delete",
|
|
"serverCardAuthenticated": "Authenticated",
|
|
"serverCardLastSynced": "Last synced: {time}",
|
|
"@serverCardLastSynced": {
|
|
"placeholders": {
|
|
"time": { "type": "String" }
|
|
}
|
|
},
|
|
|
|
"offlineSemanticLabel": "Offline",
|
|
|
|
"nextInSeriesNext": "Next",
|
|
"nextInSeriesFinished": "Finished",
|
|
"nextInSeriesBackToDetails": "Back to details",
|
|
"nextInSeriesBackToLibrary": "Back to library",
|
|
|
|
"routeNotFound": "Page not found: {uri}",
|
|
"@routeNotFound": {
|
|
"placeholders": {
|
|
"uri": { "type": "String" }
|
|
}
|
|
},
|
|
|
|
"commonCancel": "Cancel",
|
|
"commonDelete": "Delete",
|
|
"commonRemove": "Remove",
|
|
|
|
"timeJustNow": "just now",
|
|
"timeMinutesAgo": "{minutes}m ago",
|
|
"@timeMinutesAgo": {
|
|
"placeholders": {
|
|
"minutes": { "type": "int" }
|
|
}
|
|
},
|
|
"timeHoursAgo": "{hours}h ago",
|
|
"@timeHoursAgo": {
|
|
"placeholders": {
|
|
"hours": { "type": "int" }
|
|
}
|
|
},
|
|
"timeDaysAgo": "{days}d ago",
|
|
"@timeDaysAgo": {
|
|
"placeholders": {
|
|
"days": { "type": "int" }
|
|
}
|
|
},
|
|
"timeWeeksAgo": "{weeks}w ago",
|
|
"@timeWeeksAgo": {
|
|
"placeholders": {
|
|
"weeks": { "type": "int" }
|
|
}
|
|
},
|
|
"timeMonthsAgo": "{months}mo ago",
|
|
"@timeMonthsAgo": {
|
|
"placeholders": {
|
|
"months": { "type": "int" }
|
|
}
|
|
},
|
|
"timeYearsAgo": "{years}y ago",
|
|
"@timeYearsAgo": {
|
|
"placeholders": {
|
|
"years": { "type": "int" }
|
|
}
|
|
},
|
|
"timeToday": "Today",
|
|
"timeYesterday": "Yesterday",
|
|
"timeMinAgo": "{minutes} min ago",
|
|
"@timeMinAgo": {
|
|
"placeholders": {
|
|
"minutes": { "type": "int" }
|
|
}
|
|
},
|
|
"timeHoursAgoLong": "{count} {count, plural, =1{hour} other{hours}} ago",
|
|
"@timeHoursAgoLong": {
|
|
"placeholders": {
|
|
"count": { "type": "int" }
|
|
}
|
|
},
|
|
"timeDaysAgoLong": "{days} days ago",
|
|
"@timeDaysAgoLong": {
|
|
"placeholders": {
|
|
"days": { "type": "int" }
|
|
}
|
|
},
|
|
|
|
"downloadAll": "Download All",
|
|
"downloadChapter": "Download Chapter",
|
|
"downloadCancel": "Cancel Download",
|
|
"downloadDelete": "Delete Download",
|
|
"downloadDeleteSeries": "Delete Downloaded Series",
|
|
"downloadDeleteSeriesConfirmation": "Delete \"{title}\" and all its downloaded files? This cannot be undone.",
|
|
"@downloadDeleteSeriesConfirmation": {
|
|
"placeholders": {
|
|
"title": { "type": "String" }
|
|
}
|
|
},
|
|
"downloadDeleteChapterConfirmation": "Delete the downloaded file for \"{title}\"?",
|
|
"@downloadDeleteChapterConfirmation": {
|
|
"placeholders": {
|
|
"title": { "type": "String" }
|
|
}
|
|
},
|
|
"downloadStarting": "Starting download...",
|
|
"downloadComplete": "Download complete",
|
|
"downloadFailed": "Download failed",
|
|
"downloadCancelled": "Download cancelled",
|
|
"downloadInProgress": "Downloading...",
|
|
"downloadChaptersCount": "{downloaded}/{total} chapters",
|
|
"@downloadChaptersCount": {
|
|
"placeholders": {
|
|
"downloaded": { "type": "int" },
|
|
"total": { "type": "int" }
|
|
}
|
|
},
|
|
"downloadConfirmTitle": "Download Series",
|
|
"downloadConfirmMessage": "Download {count} chapters for offline reading?",
|
|
"@downloadConfirmMessage": {
|
|
"placeholders": {
|
|
"count": { "type": "int" }
|
|
}
|
|
},
|
|
"downloadConfirmStart": "Download",
|
|
|
|
"libraryDownloaded": "Downloaded",
|
|
"libraryNoDownloads": "No Downloads",
|
|
"libraryNoDownloadsSubtitle": "Download series from the browse screen for offline reading",
|
|
|
|
"downloadedSeriesDetailTitle": "Downloaded Series",
|
|
"downloadedSeriesChapters": "{count} chapters",
|
|
"@downloadedSeriesChapters": {
|
|
"placeholders": {
|
|
"count": { "type": "int" }
|
|
}
|
|
},
|
|
"downloadedChapterReady": "Ready to read",
|
|
"downloadedChapterPending": "Pending",
|
|
"downloadedChapterFailed": "Failed",
|
|
"downloadRetryAll": "Retry all failed",
|
|
"downloadRetryFailed": "Failed - tap to retry",
|
|
"downloadingPages": "Page {downloaded}/{total}",
|
|
"@downloadingPages": {
|
|
"placeholders": {
|
|
"downloaded": { "type": "int" },
|
|
"total": { "type": "int" }
|
|
}
|
|
},
|
|
"downloadFailedCount": "{count} failed",
|
|
"@downloadFailedCount": {
|
|
"placeholders": {
|
|
"count": { "type": "int" }
|
|
}
|
|
},
|
|
|
|
"settingsDownloadedContent": "Downloaded content",
|
|
"settingsDownloadedContentSubtitle": "Manage offline downloads",
|
|
"settingsClearAllDownloads": "Clear all downloads",
|
|
"settingsClearAllDownloadsConfirmation": "Delete all downloaded content? This cannot be undone.",
|
|
"settingsDownloadSize": "Using {size}",
|
|
"@settingsDownloadSize": {
|
|
"placeholders": {
|
|
"size": { "type": "String" }
|
|
}
|
|
},
|
|
"settingsDownloadsCleared": "All downloads cleared"
|
|
}
|