worldhopper/lib/l10n/app_en.arb
Felipe M. 58a562abe8
feat: refactor server software abstraction with Kavita REST API integration
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
2026-04-06 17:46:48 +02:00

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"
}