feat: add i18n support (FR/EN) to backoffice with English as default

Implement full internationalization for the Next.js backoffice:
- i18n infrastructure: type-safe dictionaries (fr.ts/en.ts), cookie-based locale detection, React Context for client components, server-side translation helper
- Language selector in Settings page (General tab) with cookie + DB persistence
- All ~35 pages and components translated via t() / useTranslation()
- Default locale set to English, French available via settings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 19:39:01 +01:00
parent 055c376222
commit d4f87c4044
43 changed files with 2024 additions and 693 deletions

View File

@@ -0,0 +1,555 @@
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",
// 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}}",
// 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",
// 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.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.autoScan": "Auto scan",
"libraryActions.fileWatch": "File watch ⚡",
"libraryActions.schedule": "📅 Schedule",
"libraryActions.provider": "Provider",
"libraryActions.fallback": "Fallback",
"libraryActions.default": "Default",
"libraryActions.none": "None",
"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.fullRebuild": "Full rebuild",
"jobs.generateThumbnails": "Generate thumbnails",
"jobs.regenerateThumbnails": "Regenerate thumbnails",
"jobs.batchMetadata": "Batch metadata",
"jobs.referenceTitle": "Job types reference",
"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.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.files": "Files",
"jobsList.thumbnails": "Thumbnails",
"jobsList.duration": "Duration",
"jobsList.created": "Created",
"jobsList.actions": "Actions",
// Job row
"jobRow.showProgress": "Show progress",
"jobRow.hideProgress": "Hide progress",
"jobRow.scanned": "{{count}} scanned",
"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.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.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.rebuildLabel": "Incremental indexing",
"jobType.rebuildDesc": "Scans new/modified files, analyzes them, and generates missing thumbnails.",
"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.",
// 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 - 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",
};
export default en;