worldhopper/lib/l10n/app_en.arb
Felipe M. bb579719f9
All checks were successful
ci/woodpecker/pr/pr Pipeline was successful
fix: prevent double-save on exit, surface KOReader sync auth failures
- Add guard flag to prevent both onPopInvokedWithResult and dispose()
  from saving progress (double DB writes + double sync pushes)
- Capture ref-dependent values synchronously in _saveProgress before
  any await to prevent accessing disposed ref after super.dispose()
- Guard ref.invalidate() calls with mounted check for dispose safety
- Add KoreaderSyncAuthException so 401 errors in getProgress and
  updateProgress propagate instead of being silently swallowed
- Show a warning snackbar (once per session) when auth fails so the
  user knows sync credentials need updating

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 00:12:06 +01:00

462 lines
16 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",
"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",
"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.",
"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",
"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.",
"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" }
}
},
"koreaderSyncToggle": "KOReader API Sync",
"koreaderSyncToggleSubtitle": "Sync EPUB reading progress with a KOReader-compatible server",
"koreaderSyncUrl": "Sync Server URL",
"koreaderSyncUrlHint": "https://sync.example.com",
"koreaderSyncUsername": "Sync Username",
"koreaderSyncPassword": "Sync Password",
"koreaderSyncTestConnection": "Test Connection",
"koreaderSyncTestSuccess": "Connection successful! Authenticated as {username}.",
"@koreaderSyncTestSuccess": {
"placeholders": {
"username": { "type": "String" }
}
},
"koreaderSyncTestFailed": "Connection failed: {error}",
"@koreaderSyncTestFailed": {
"placeholders": {
"error": { "type": "String" }
}
},
"koreaderSyncValidationUrlRequired": "Sync server URL is required when KOReader sync is enabled",
"koreaderSyncValidationUrlInvalid": "Please enter a valid URL",
"koreaderSyncValidationUsernameRequired": "Sync username is required",
"koreaderSyncValidationPasswordRequired": "Sync password is required",
"koreaderSyncAuthFailed": "KOReader sync: authentication failed. Check your server credentials.",
"koreaderSyncHelp": "Connect to a KOReader-compatible sync server to synchronize EPUB reading positions across devices.",
"koreaderSyncResumeInfo": "KOReader sync is enabled. Your reading position will be automatically restored from the sync server when you open this book.",
"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",
"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" }
}
}
}