diff --git a/src/app/downloads/page.tsx b/src/app/downloads/page.tsx index 5fdfcc0..8750d34 100644 --- a/src/app/downloads/page.tsx +++ b/src/app/downloads/page.tsx @@ -1,11 +1,9 @@ -import { PageHeader } from "@/components/layout/PageHeader"; import { DownloadManager } from "@/components/downloads/DownloadManager"; import { withPageTiming } from "@/lib/hoc/withPageTiming"; function DownloadsPage() { return ( <> - ); diff --git a/src/components/downloads/DownloadManager.tsx b/src/components/downloads/DownloadManager.tsx index 7f487f2..3fb5fb0 100644 --- a/src/components/downloads/DownloadManager.tsx +++ b/src/components/downloads/DownloadManager.tsx @@ -11,6 +11,7 @@ import { Progress } from "@/components/ui/progress"; import Image from "next/image"; import Link from "next/link"; import { BookOfflineButton } from "@/components/ui/book-offline-button"; +import { useTranslate } from "@/hooks/useTranslate"; type BookStatus = "idle" | "downloading" | "available" | "error"; @@ -30,6 +31,7 @@ export function DownloadManager() { const [downloadedBooks, setDownloadedBooks] = useState([]); const [isLoading, setIsLoading] = useState(true); const { toast } = useToast(); + const { t } = useTranslate(); const getStorageKey = useCallback((bookId: string) => `book-status-${bookId}`, []); @@ -116,26 +118,25 @@ export function DownloadManager() { localStorage.removeItem(getStorageKey(book.id)); setDownloadedBooks((prev) => prev.filter((b) => b.book.id !== book.id)); toast({ - title: "Livre supprimé", - description: "Le livre n'est plus disponible hors ligne", + title: t("downloads.toast.deleted"), + description: t("downloads.toast.deletedDesc"), }); } catch (error) { console.error("Erreur lors de la suppression du livre:", error); toast({ - title: "Erreur", - description: "Une erreur est survenue lors de la suppression", + title: t("downloads.toast.error"), + description: t("downloads.toast.errorDesc"), variant: "destructive", }); } }; const handleRetryDownload = async (book: KomgaBook) => { - // Réinitialise le statut et laisse le composant BookOfflineButton gérer le téléchargement localStorage.removeItem(getStorageKey(book.id)); setDownloadedBooks((prev) => prev.filter((b) => b.book.id !== book.id)); toast({ - title: "Téléchargement relancé", - description: "Le téléchargement va reprendre depuis le début", + title: t("downloads.toast.retry"), + description: t("downloads.toast.retryDesc"), }); }; @@ -148,59 +149,57 @@ export function DownloadManager() { } return ( - -
- - Tous ({downloadedBooks.length}) - - En cours ({downloadedBooks.filter((b) => b.status.status === "downloading").length}) - - - Disponibles ({downloadedBooks.filter((b) => b.status.status === "available").length}) - - - Erreurs ({downloadedBooks.filter((b) => b.status.status === "error").length}) - - - {downloadedBooks.some((b) => b.status.status === "error") && ( - + <> +
+

{t("downloads.page.title")}

+ {t("downloads.page.description") && ( +

{t("downloads.page.description")}

)}
+ +
+ + + {t("downloads.tabs.all", { count: downloadedBooks.length })} + + + {t("downloads.tabs.downloading", { + count: downloadedBooks.filter((b) => b.status.status === "downloading").length, + })} + + + {t("downloads.tabs.available", { + count: downloadedBooks.filter((b) => b.status.status === "available").length, + })} + + + {t("downloads.tabs.error", { + count: downloadedBooks.filter((b) => b.status.status === "error").length, + })} + + + {downloadedBooks.some((b) => b.status.status === "error") && ( + + )} +
- - {downloadedBooks.map(({ book, status }) => ( - handleDeleteBook(book)} - onRetry={() => handleRetryDownload(book)} - /> - ))} - {downloadedBooks.length === 0 && ( -

Aucun livre téléchargé

- )} -
- - - {downloadedBooks - .filter((b) => b.status.status === "downloading") - .map(({ book, status }) => ( + + {downloadedBooks.map(({ book, status }) => ( handleRetryDownload(book)} /> ))} - {downloadedBooks.filter((b) => b.status.status === "downloading").length === 0 && ( -

Aucun téléchargement en cours

- )} -
+ {downloadedBooks.length === 0 && ( +

{t("downloads.empty.all")}

+ )} +
- - {downloadedBooks - .filter((b) => b.status.status === "available") - .map(({ book, status }) => ( - handleDeleteBook(book)} - onRetry={() => handleRetryDownload(book)} - /> - ))} - {downloadedBooks.filter((b) => b.status.status === "available").length === 0 && ( -

Aucun livre disponible hors ligne

- )} -
+ + {downloadedBooks + .filter((b) => b.status.status === "downloading") + .map(({ book, status }) => ( + handleDeleteBook(book)} + onRetry={() => handleRetryDownload(book)} + /> + ))} + {downloadedBooks.filter((b) => b.status.status === "downloading").length === 0 && ( +

+ {t("downloads.empty.downloading")} +

+ )} +
- - {downloadedBooks - .filter((b) => b.status.status === "error") - .map(({ book, status }) => ( - handleDeleteBook(book)} - onRetry={() => handleRetryDownload(book)} - /> - ))} - {downloadedBooks.filter((b) => b.status.status === "error").length === 0 && ( -

Aucune erreur

- )} -
-
+ + {downloadedBooks + .filter((b) => b.status.status === "available") + .map(({ book, status }) => ( + handleDeleteBook(book)} + onRetry={() => handleRetryDownload(book)} + /> + ))} + {downloadedBooks.filter((b) => b.status.status === "available").length === 0 && ( +

+ {t("downloads.empty.available")} +

+ )} +
+ + + {downloadedBooks + .filter((b) => b.status.status === "error") + .map(({ book, status }) => ( + handleDeleteBook(book)} + onRetry={() => handleRetryDownload(book)} + /> + ))} + {downloadedBooks.filter((b) => b.status.status === "error").length === 0 && ( +

{t("downloads.empty.error")}

+ )} +
+ + ); } @@ -259,9 +280,11 @@ interface BookDownloadCardProps { } function BookDownloadCard({ book, status, onDelete, onRetry }: BookDownloadCardProps) { + const { t } = useTranslate(); + const formatSize = (bytes: number) => { const mb = bytes / (1024 * 1024); - return `${mb.toFixed(1)} Mo`; + return t("downloads.info.size", { size: mb.toFixed(1) }); }; const getStatusIcon = (status: BookStatus) => { @@ -278,16 +301,7 @@ function BookDownloadCard({ book, status, onDelete, onRetry }: BookDownloadCardP }; const getStatusText = (status: BookStatus) => { - switch (status) { - case "downloading": - return "En cours de téléchargement"; - case "available": - return "Disponible hors ligne"; - case "error": - return "Erreur de téléchargement"; - default: - return "Non téléchargé"; - } + return t(`downloads.status.${status}`); }; return ( @@ -296,7 +310,7 @@ function BookDownloadCard({ book, status, onDelete, onRetry }: BookDownloadCardP
{`Couverture

- {book.metadata?.title || `Tome ${book.metadata?.number}`} + {book.metadata?.title || t("books.title", { number: book.metadata?.number })}

@@ -317,10 +331,11 @@ function BookDownloadCard({ book, status, onDelete, onRetry }: BookDownloadCardP {status.status === "downloading" - ? `${Math.floor((status.progress * book.media.pagesCount) / 100)}/${ - book.media.pagesCount - } pages` - : `${book.media.pagesCount} pages`} + ? t("downloads.info.pages", { + current: Math.floor((status.progress * book.media.pagesCount) / 100), + total: book.media.pagesCount, + }) + : t("downloads.info.totalPages", { count: book.media.pagesCount })}
@@ -342,7 +357,7 @@ function BookDownloadCard({ book, status, onDelete, onRetry }: BookDownloadCardP variant="ghost" size="icon" onClick={onRetry} - title="Réessayer" + title={t("downloads.actions.retry")} className="h-8 w-8 p-0 rounded-br-lg rounded-tl-lg" > @@ -354,7 +369,7 @@ function BookDownloadCard({ book, status, onDelete, onRetry }: BookDownloadCardP variant="ghost" size="icon" onClick={onDelete} - title="Supprimer" + title={t("downloads.actions.delete")} className="h-8 w-8 p-0 rounded-br-lg rounded-tl-lg" > diff --git a/src/components/layout/PageHeader.tsx b/src/components/layout/PageHeader.tsx deleted file mode 100644 index 4f4c2d6..0000000 --- a/src/components/layout/PageHeader.tsx +++ /dev/null @@ -1,13 +0,0 @@ -interface PageHeaderProps { - title: string; - description?: string; -} - -export function PageHeader({ title, description }: PageHeaderProps) { - return ( -
-

{title}

- {description &&

{description}

} -
- ); -} diff --git a/src/i18n/messages/en/common.json b/src/i18n/messages/en/common.json index d1df69c..c849e8b 100644 --- a/src/i18n/messages/en/common.json +++ b/src/i18n/messages/en/common.json @@ -174,5 +174,49 @@ "unread": "Unread" }, "loading": "Loading..." + }, + "downloads": { + "page": { + "title": "Downloads", + "description": "Manage your offline available books" + }, + "tabs": { + "all": "All ({count})", + "downloading": "Downloading ({count})", + "available": "Available ({count})", + "error": "Errors ({count})" + }, + "empty": { + "all": "No downloaded books", + "downloading": "No downloads in progress", + "available": "No books available offline", + "error": "No errors" + }, + "actions": { + "retryAll": "Retry all", + "retry": "Retry", + "delete": "Delete" + }, + "status": { + "downloading": "Downloading", + "available": "Available offline", + "error": "Download error", + "idle": "Not downloaded" + }, + "toast": { + "deleted": "Book deleted", + "deletedDesc": "The book is no longer available offline", + "error": "Error", + "errorDesc": "An error occurred while deleting", + "retryAll": "Retrying downloads", + "retryAllDesc": "{count} download(s) restarted", + "retryDesc": "Download will start from the beginning", + "retry": "Download restarted" + }, + "info": { + "size": "{size} MB", + "pages": "{current}/{total} pages", + "totalPages": "{count} pages" + } } } diff --git a/src/i18n/messages/fr/common.json b/src/i18n/messages/fr/common.json index 2562911..6febf4b 100644 --- a/src/i18n/messages/fr/common.json +++ b/src/i18n/messages/fr/common.json @@ -174,5 +174,49 @@ "unread": "À lire" }, "loading": "Chargement..." + }, + "downloads": { + "page": { + "title": "Téléchargements", + "description": "Gérez vos livres disponibles hors ligne" + }, + "tabs": { + "all": "Tous ({count})", + "downloading": "En cours ({count})", + "available": "Disponibles ({count})", + "error": "Erreurs ({count})" + }, + "empty": { + "all": "Aucun livre téléchargé", + "downloading": "Aucun téléchargement en cours", + "available": "Aucun livre disponible hors ligne", + "error": "Aucune erreur" + }, + "actions": { + "retryAll": "Tout relancer", + "retry": "Réessayer", + "delete": "Supprimer" + }, + "status": { + "downloading": "En cours de téléchargement", + "available": "Disponible hors ligne", + "error": "Erreur de téléchargement", + "idle": "Non téléchargé" + }, + "toast": { + "deleted": "Livre supprimé", + "deletedDesc": "Le livre n'est plus disponible hors ligne", + "error": "Erreur", + "errorDesc": "Une erreur est survenue lors de la suppression", + "retryAll": "Relance des téléchargements", + "retryAllDesc": "{count} téléchargement(s) relancé(s)", + "retryDesc": "Le téléchargement va reprendre depuis le début", + "retry": "Téléchargement relancé" + }, + "info": { + "size": "{size} Mo", + "pages": "{current}/{total} pages", + "totalPages": "{count} pages" + } } }