forked from akai/readest
Resolves #4615. Re-importing updated serials left the app-generated Books/<hash>/ folder (config.json reading progress/notes, nav.json, cover) on disk after a normal delete, forcing a manual cleanup. "Purge Data" now does a Cloud & Device delete AND wipes the whole directory in one action. The book detail action row is redesigned to Edit · Download · Upload · Delete · More (hamburger): - Goodreads, Share, and Export move into the hamburger "More" menu. - Share is enabled only when signed in and the local file exists; Export is enabled when the local file exists (kept on every platform since the bottom-bar Send is mobile/macOS-only). - Purge Data is the red entry in the Delete menu, behind a strong confirm. Implementation: - DeleteAction gains 'purge'; cloudService.deleteBook('purge') removes the in-place source file and removeDir's the whole Books/<hash>/ folder, clearing downloadedAt and leaving the tombstone + queued cloud delete to the page (mirrors 'both'/'local'). - The library page wires handleBookDelete('purge'); BookDetailModal adds the purge confirm config + share/export handlers and gates Share on auth. Tests: cloud-service purge cases, BookDetailView More-menu + Purge tests. i18n: 9 new keys translated across all 33 locales. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1889,5 +1889,14 @@
|
||||
"Clear Pending": "مسح قيد الانتظار",
|
||||
"Reading statistics": "إحصائيات القراءة",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "وقت القراءة والصفحات المقروءة، تتم مزامنتها عبر أجهزتك و KOReader.",
|
||||
"Auto Sync": "مزامنة تلقائية"
|
||||
"Auto Sync": "مزامنة تلقائية",
|
||||
"Purged book data: {{title}}": "تم محو بيانات الكتاب: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "فشل محو بيانات الكتاب: {{title}}",
|
||||
"Purge Book Data": "محو جميع بيانات الكتاب",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "سيؤدي هذا إلى محو الكتاب وجميع بياناته نهائيًا، بما في ذلك تقدم القراءة والملاحظات والإشارات المرجعية. لا يمكن التراجع عن هذا الإجراء.",
|
||||
"Purge Data": "محو جميع البيانات",
|
||||
"Erase the book and all its data, including reading progress": "محو الكتاب وجميع بياناته، بما في ذلك تقدم القراءة",
|
||||
"More Actions": "إجراءات أخرى",
|
||||
"Sign in and make the book available to share it": "سجّل الدخول واجعل الكتاب متاحًا لمشاركته",
|
||||
"Download the book to export it": "نزّل الكتاب لتصديره"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "অপেক্ষমাণ মুছুন",
|
||||
"Reading statistics": "পড়ার পরিসংখ্যান",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "পড়ার সময় এবং পড়া পৃষ্ঠা, আপনার ডিভাইস এবং KOReader জুড়ে সিঙ্ক করা হয়।",
|
||||
"Auto Sync": "স্বয়ংক্রিয় সিঙ্ক"
|
||||
"Auto Sync": "স্বয়ংক্রিয় সিঙ্ক",
|
||||
"Purged book data: {{title}}": "বইয়ের ডেটা মুছে ফেলা হয়েছে: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "বইয়ের ডেটা মুছতে ব্যর্থ: {{title}}",
|
||||
"Purge Book Data": "বইয়ের সমস্ত ডেটা মুছুন",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "এটি বইটি এবং পড়ার অগ্রগতি, নোট ও বুকমার্ক সহ এর সমস্ত ডেটা স্থায়ীভাবে মুছে ফেলবে। এটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"Purge Data": "সমস্ত ডেটা মুছুন",
|
||||
"Erase the book and all its data, including reading progress": "পড়ার অগ্রগতিসহ বই ও এর সমস্ত ডেটা মুছে ফেলুন",
|
||||
"More Actions": "আরও ক্রিয়া",
|
||||
"Sign in and make the book available to share it": "শেয়ার করতে সাইন ইন করুন এবং বইটি উপলব্ধ করুন",
|
||||
"Download the book to export it": "এক্সপোর্ট করতে বইটি ডাউনলোড করুন"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "སྒུག་བཞིན་པ་གསལ་བ་",
|
||||
"Reading statistics": "ཀློག་འདོན་གྱི་གྲངས་ཐོ།",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "ཀློག་འདོན་གྱི་དུས་ཚོད་དང་ཀློག་ཟིན་པའི་ཤོག་གྲངས། ཁྱེད་ཀྱི་སྒྲིག་ཆས་དང་ KOReader བར་མཉམ་སྒྲིག་བྱེད།",
|
||||
"Auto Sync": "རང་འགུལ་སྤྲི་དོན།"
|
||||
"Auto Sync": "རང་འགུལ་སྤྲི་དོན།",
|
||||
"Purged book data: {{title}}": "དཔེ་དེབ་ཀྱི་གཞི་གྲངས་བསུབ་ཟིན། {{title}}",
|
||||
"Failed to purge book data: {{title}}": "དཔེ་དེབ་ཀྱི་གཞི་གྲངས་བསུབ་མ་ཐུབ། {{title}}",
|
||||
"Purge Book Data": "དཔེ་དེབ་ཀྱི་གཞི་གྲངས་ཡོངས་སུ་བསུབ།",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "འདིས་དཔེ་དེབ་དང་ཀློག་འདོན་གྱི་འཕེལ་རིམ། ཟིན་ཐོ། དེབ་རྟགས་བཅས་ཀྱི་གཞི་གྲངས་ཡོངས་རྫོགས་གཏན་འཁེལ་དུ་བསུབ་པ་ཡིན། འདི་ཕྱིར་བསྒྱུར་མི་ཐུབ།",
|
||||
"Purge Data": "གཞི་གྲངས་ཡོངས་སུ་བསུབ།",
|
||||
"Erase the book and all its data, including reading progress": "དཔེ་དེབ་དང་ཀློག་འདོན་གྱི་འཕེལ་རིམ་བཅས་ཀྱི་གཞི་གྲངས་ཡོངས་སུ་བསུབ།",
|
||||
"More Actions": "བྱ་སྤྱོད་གཞན་དག",
|
||||
"Sign in and make the book available to share it": "ནང་འཛུལ་བྱས་ནས་དཔེ་དེབ་མཁོ་སྤྲོད་རུང་བར་བཟོས་ནས་མཉམ་སྤྱོད་བྱོས།",
|
||||
"Download the book to export it": "ཕྱིར་འདྲེན་བྱེད་པར་དཔེ་དེབ་ཕབ་ལེན་བྱོས།"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "Ausstehende löschen",
|
||||
"Reading statistics": "Lesestatistik",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Lesezeit und gelesene Seiten, synchronisiert über deine Geräte und KOReader.",
|
||||
"Auto Sync": "Automatische Synchronisierung"
|
||||
"Auto Sync": "Automatische Synchronisierung",
|
||||
"Purged book data: {{title}}": "Buchdaten gelöscht: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Buchdaten konnten nicht gelöscht werden: {{title}}",
|
||||
"Purge Book Data": "Buchdaten endgültig löschen",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Dadurch werden das Buch und alle zugehörigen Daten – einschließlich Lesefortschritt, Notizen und Lesezeichen – endgültig gelöscht. Dies kann nicht rückgängig gemacht werden.",
|
||||
"Purge Data": "Alle Daten löschen",
|
||||
"Erase the book and all its data, including reading progress": "Buch und alle Daten löschen, einschließlich Lesefortschritt",
|
||||
"More Actions": "Weitere Aktionen",
|
||||
"Sign in and make the book available to share it": "Melde dich an und mache das Buch verfügbar, um es zu teilen",
|
||||
"Download the book to export it": "Lade das Buch herunter, um es zu exportieren"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "Εκκαθάριση σε αναμονή",
|
||||
"Reading statistics": "Στατιστικά ανάγνωσης",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Χρόνος ανάγνωσης και σελίδες που διαβάστηκαν, συγχρονισμένα στις συσκευές σας και το KOReader.",
|
||||
"Auto Sync": "Αυτόματος συγχρονισμός"
|
||||
"Auto Sync": "Αυτόματος συγχρονισμός",
|
||||
"Purged book data: {{title}}": "Τα δεδομένα του βιβλίου διαγράφηκαν: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Αποτυχία διαγραφής δεδομένων βιβλίου: {{title}}",
|
||||
"Purge Book Data": "Διαγραφή δεδομένων βιβλίου",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Αυτό διαγράφει οριστικά το βιβλίο και όλα τα δεδομένα του, συμπεριλαμβανομένης της προόδου ανάγνωσης, των σημειώσεων και των σελιδοδεικτών. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.",
|
||||
"Purge Data": "Διαγραφή όλων των δεδομένων",
|
||||
"Erase the book and all its data, including reading progress": "Διαγράφει το βιβλίο και όλα τα δεδομένα του, συμπεριλαμβανομένης της προόδου ανάγνωσης",
|
||||
"More Actions": "Περισσότερες ενέργειες",
|
||||
"Sign in and make the book available to share it": "Συνδεθείτε και κάντε το βιβλίο διαθέσιμο για να το μοιραστείτε",
|
||||
"Download the book to export it": "Κατεβάστε το βιβλίο για να το εξαγάγετε"
|
||||
}
|
||||
|
||||
@@ -1790,5 +1790,14 @@
|
||||
"Clear Pending": "Limpiar pendientes",
|
||||
"Reading statistics": "Estadísticas de lectura",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Tiempo de lectura y páginas leídas, sincronizados entre tus dispositivos y KOReader.",
|
||||
"Auto Sync": "Sincronización automática"
|
||||
"Auto Sync": "Sincronización automática",
|
||||
"Purged book data: {{title}}": "Datos del libro borrados: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "No se pudieron borrar los datos del libro: {{title}}",
|
||||
"Purge Book Data": "Borrar todos los datos del libro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Esto borra permanentemente el libro y todos sus datos, incluido el progreso de lectura, las notas y los marcadores. Esta acción no se puede deshacer.",
|
||||
"Purge Data": "Borrar todos los datos",
|
||||
"Erase the book and all its data, including reading progress": "Borra el libro y todos sus datos, incluido el progreso de lectura",
|
||||
"More Actions": "Más acciones",
|
||||
"Sign in and make the book available to share it": "Inicia sesión y ten el libro disponible para compartirlo",
|
||||
"Download the book to export it": "Descarga el libro para exportarlo"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "پاک کردن در انتظارها",
|
||||
"Reading statistics": "آمار مطالعه",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "زمان مطالعه و صفحات خواندهشده، همگامسازیشده در دستگاههای شما و KOReader.",
|
||||
"Auto Sync": "همگامسازی خودکار"
|
||||
"Auto Sync": "همگامسازی خودکار",
|
||||
"Purged book data: {{title}}": "دادههای کتاب پاک شد: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "پاکسازی دادههای کتاب ناموفق بود: {{title}}",
|
||||
"Purge Book Data": "پاکسازی دادههای کتاب",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "این کار کتاب و تمام دادههای آن، شامل پیشرفت مطالعه، یادداشتها و نشانکها را برای همیشه پاک میکند. این عمل قابل بازگشت نیست.",
|
||||
"Purge Data": "پاکسازی دادهها",
|
||||
"Erase the book and all its data, including reading progress": "کتاب و تمام دادههای آن، شامل پیشرفت مطالعه را پاک میکند",
|
||||
"More Actions": "اقدامات بیشتر",
|
||||
"Sign in and make the book available to share it": "برای اشتراکگذاری، وارد شوید و کتاب را در دسترس قرار دهید",
|
||||
"Download the book to export it": "برای خروجی گرفتن، کتاب را دانلود کنید"
|
||||
}
|
||||
|
||||
@@ -1790,5 +1790,14 @@
|
||||
"Clear Pending": "Effacer les en attente",
|
||||
"Reading statistics": "Statistiques de lecture",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Temps de lecture et pages lues, synchronisés sur vos appareils et KOReader.",
|
||||
"Auto Sync": "Synchronisation automatique"
|
||||
"Auto Sync": "Synchronisation automatique",
|
||||
"Purged book data: {{title}}": "Données du livre purgées : {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Échec de la purge des données du livre : {{title}}",
|
||||
"Purge Book Data": "Purger les données du livre",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Cette action supprime définitivement le livre et toutes ses données, y compris la progression de lecture, les notes et les signets. Cette action est irréversible.",
|
||||
"Purge Data": "Purger les données",
|
||||
"Erase the book and all its data, including reading progress": "Supprime le livre et toutes ses données, y compris la progression de lecture",
|
||||
"More Actions": "Plus d'actions",
|
||||
"Sign in and make the book available to share it": "Connectez-vous et rendez le livre disponible pour le partager",
|
||||
"Download the book to export it": "Téléchargez le livre pour l'exporter"
|
||||
}
|
||||
|
||||
@@ -1790,5 +1790,14 @@
|
||||
"Clear Pending": "נקה בהמתנה",
|
||||
"Reading statistics": "סטטיסטיקת קריאה",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "זמן קריאה ועמודים שנקראו, מסונכרנים בין המכשירים שלך ו-KOReader.",
|
||||
"Auto Sync": "סנכרון אוטומטי"
|
||||
"Auto Sync": "סנכרון אוטומטי",
|
||||
"Purged book data: {{title}}": "נתוני הספר נמחקו: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "מחיקת נתוני הספר נכשלה: {{title}}",
|
||||
"Purge Book Data": "מחיקת כל נתוני הספר",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "פעולה זו מוחקת לצמיתות את הספר ואת כל הנתונים שלו, כולל התקדמות הקריאה, ההערות והסימניות. לא ניתן לבטל פעולה זו.",
|
||||
"Purge Data": "מחק את כל הנתונים",
|
||||
"Erase the book and all its data, including reading progress": "מחיקת הספר וכל הנתונים שלו, כולל התקדמות הקריאה",
|
||||
"More Actions": "פעולות נוספות",
|
||||
"Sign in and make the book available to share it": "היכנס והפוך את הספר לזמין כדי לשתף אותו",
|
||||
"Download the book to export it": "הורד את הספר כדי לייצא אותו"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "लंबित साफ़ करें",
|
||||
"Reading statistics": "पठन सांख्यिकी",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "पढ़ने का समय और पढ़े गए पृष्ठ, आपके डिवाइसों और KOReader के बीच सिंक किए गए।",
|
||||
"Auto Sync": "स्वतः सिंक"
|
||||
"Auto Sync": "स्वतः सिंक",
|
||||
"Purged book data: {{title}}": "पुस्तक का डेटा मिटाया गया: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "पुस्तक का डेटा मिटाने में विफल: {{title}}",
|
||||
"Purge Book Data": "पुस्तक का सारा डेटा मिटाएँ",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "इससे पुस्तक और उसका सारा डेटा, जिसमें पढ़ने की प्रगति, नोट्स और बुकमार्क शामिल हैं, स्थायी रूप से मिट जाएगा। इसे पूर्ववत नहीं किया जा सकता।",
|
||||
"Purge Data": "सारा डेटा मिटाएँ",
|
||||
"Erase the book and all its data, including reading progress": "पढ़ने की प्रगति सहित पुस्तक और उसका सारा डेटा मिटाएँ",
|
||||
"More Actions": "अधिक क्रियाएँ",
|
||||
"Sign in and make the book available to share it": "साझा करने के लिए साइन इन करें और पुस्तक उपलब्ध कराएँ",
|
||||
"Download the book to export it": "निर्यात करने के लिए पुस्तक डाउनलोड करें"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "Függőben lévők törlése",
|
||||
"Reading statistics": "Olvasási statisztika",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Olvasási idő és elolvasott oldalak, szinkronizálva az eszközei és a KOReader között.",
|
||||
"Auto Sync": "Automatikus szinkronizálás"
|
||||
"Auto Sync": "Automatikus szinkronizálás",
|
||||
"Purged book data: {{title}}": "Könyv adatai törölve: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "A könyv adatainak törlése sikertelen: {{title}}",
|
||||
"Purge Book Data": "Könyv összes adatának törlése",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Ez véglegesen törli a könyvet és minden adatát, beleértve az olvasási előrehaladást, a jegyzeteket és a könyvjelzőket. A művelet nem vonható vissza.",
|
||||
"Purge Data": "Összes adat törlése",
|
||||
"Erase the book and all its data, including reading progress": "Törli a könyvet és minden adatát, beleértve az olvasási előrehaladást",
|
||||
"More Actions": "További műveletek",
|
||||
"Sign in and make the book available to share it": "Jelentkezz be, és tedd elérhetővé a könyvet a megosztáshoz",
|
||||
"Download the book to export it": "Töltsd le a könyvet az exportáláshoz"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "Hapus Menunggu",
|
||||
"Reading statistics": "Statistik Bacaan",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Waktu membaca dan halaman yang dibaca, disinkronkan di seluruh perangkat Anda dan KOReader.",
|
||||
"Auto Sync": "Sinkronisasi Otomatis"
|
||||
"Auto Sync": "Sinkronisasi Otomatis",
|
||||
"Purged book data: {{title}}": "Data buku dihapus: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Gagal menghapus data buku: {{title}}",
|
||||
"Purge Book Data": "Hapus semua data buku",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Ini akan menghapus buku secara permanen beserta semua datanya, termasuk progres baca, catatan, dan markah. Tindakan ini tidak dapat dibatalkan.",
|
||||
"Purge Data": "Hapus semua data",
|
||||
"Erase the book and all its data, including reading progress": "Menghapus buku dan semua datanya, termasuk progres baca",
|
||||
"More Actions": "Tindakan lainnya",
|
||||
"Sign in and make the book available to share it": "Masuk dan sediakan buku untuk membagikannya",
|
||||
"Download the book to export it": "Unduh buku untuk mengekspornya"
|
||||
}
|
||||
|
||||
@@ -1790,5 +1790,14 @@
|
||||
"Clear Pending": "Cancella in attesa",
|
||||
"Reading statistics": "Statistiche di lettura",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Tempo di lettura e pagine lette, sincronizzati tra i tuoi dispositivi e KOReader.",
|
||||
"Auto Sync": "Sincronizzazione automatica"
|
||||
"Auto Sync": "Sincronizzazione automatica",
|
||||
"Purged book data: {{title}}": "Dati del libro eliminati: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Impossibile eliminare i dati del libro: {{title}}",
|
||||
"Purge Book Data": "Elimina tutti i dati del libro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Questa operazione elimina definitivamente il libro e tutti i suoi dati, inclusi i progressi di lettura, le note e i segnalibri. L'operazione non può essere annullata.",
|
||||
"Purge Data": "Elimina tutti i dati",
|
||||
"Erase the book and all its data, including reading progress": "Elimina il libro e tutti i suoi dati, inclusi i progressi di lettura",
|
||||
"More Actions": "Altre azioni",
|
||||
"Sign in and make the book available to share it": "Accedi e rendi disponibile il libro per condividerlo",
|
||||
"Download the book to export it": "Scarica il libro per esportarlo"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "待機中を消去",
|
||||
"Reading statistics": "読書統計",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "読書時間と読んだページ数。デバイス間および KOReader と同期されます。",
|
||||
"Auto Sync": "自動同期"
|
||||
"Auto Sync": "自動同期",
|
||||
"Purged book data: {{title}}": "書籍データを消去しました: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "書籍データの消去に失敗しました: {{title}}",
|
||||
"Purge Book Data": "書籍データを消去",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "これにより、本と読書の進行状況・メモ・しおりを含むすべてのデータが完全に削除されます。この操作は取り消せません。",
|
||||
"Purge Data": "データを消去",
|
||||
"Erase the book and all its data, including reading progress": "本と読書の進行状況を含むすべてのデータを消去します",
|
||||
"More Actions": "その他の操作",
|
||||
"Sign in and make the book available to share it": "共有するにはサインインして書籍を利用可能にしてください",
|
||||
"Download the book to export it": "エクスポートするには書籍をダウンロードしてください"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "대기 중 항목 지우기",
|
||||
"Reading statistics": "독서 통계",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "읽은 시간과 읽은 페이지 수로, 여러 기기와 KOReader 간에 동기화됩니다.",
|
||||
"Auto Sync": "자동 동기화"
|
||||
"Auto Sync": "자동 동기화",
|
||||
"Purged book data: {{title}}": "도서 데이터를 삭제했습니다: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "도서 데이터 삭제에 실패했습니다: {{title}}",
|
||||
"Purge Book Data": "도서 데이터 완전 삭제",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "책과 읽기 진행률, 메모, 책갈피를 포함한 모든 데이터가 영구적으로 삭제됩니다. 이 작업은 되돌릴 수 없습니다.",
|
||||
"Purge Data": "데이터 완전 삭제",
|
||||
"Erase the book and all its data, including reading progress": "읽기 진행률을 포함한 책과 모든 데이터를 삭제합니다",
|
||||
"More Actions": "추가 작업",
|
||||
"Sign in and make the book available to share it": "공유하려면 로그인하고 책을 사용할 수 있도록 하세요",
|
||||
"Download the book to export it": "내보내려면 책을 다운로드하세요"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "Kosongkan Menunggu",
|
||||
"Reading statistics": "Statistik Bacaan",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Masa membaca dan halaman dibaca, disegerakkan merentas peranti anda dan KOReader.",
|
||||
"Auto Sync": "Segerak Automatik"
|
||||
"Auto Sync": "Segerak Automatik",
|
||||
"Purged book data: {{title}}": "Data buku dipadam: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Gagal memadam data buku: {{title}}",
|
||||
"Purge Book Data": "Padam semua data buku",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Ini memadamkan buku dan semua datanya secara kekal, termasuk kemajuan bacaan, nota dan penanda buku. Tindakan ini tidak boleh dibuat asal.",
|
||||
"Purge Data": "Padam semua data",
|
||||
"Erase the book and all its data, including reading progress": "Memadam buku dan semua datanya, termasuk kemajuan bacaan",
|
||||
"More Actions": "Tindakan lain",
|
||||
"Sign in and make the book available to share it": "Log masuk dan sediakan buku untuk berkongsinya",
|
||||
"Download the book to export it": "Muat turun buku untuk mengeksportnya"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "Wachtende wissen",
|
||||
"Reading statistics": "Leesstatistieken",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Leestijd en gelezen pagina's, gesynchroniseerd op je apparaten en KOReader.",
|
||||
"Auto Sync": "Automatische synchronisatie"
|
||||
"Auto Sync": "Automatische synchronisatie",
|
||||
"Purged book data: {{title}}": "Boekgegevens gewist: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Kan boekgegevens niet wissen: {{title}}",
|
||||
"Purge Book Data": "Alle boekgegevens wissen",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Hiermee worden het boek en alle bijbehorende gegevens, waaronder leesvoortgang, notities en bladwijzers, permanent gewist. Dit kan niet ongedaan worden gemaakt.",
|
||||
"Purge Data": "Alle gegevens wissen",
|
||||
"Erase the book and all its data, including reading progress": "Wist het boek en alle gegevens, inclusief leesvoortgang",
|
||||
"More Actions": "Meer acties",
|
||||
"Sign in and make the book available to share it": "Meld je aan en maak het boek beschikbaar om het te delen",
|
||||
"Download the book to export it": "Download het boek om het te exporteren"
|
||||
}
|
||||
|
||||
@@ -1823,5 +1823,14 @@
|
||||
"Clear Pending": "Wyczyść oczekujące",
|
||||
"Reading statistics": "Statystyki czytania",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Czas czytania i przeczytane strony, synchronizowane między Twoimi urządzeniami a KOReader.",
|
||||
"Auto Sync": "Automatyczna synchronizacja"
|
||||
"Auto Sync": "Automatyczna synchronizacja",
|
||||
"Purged book data: {{title}}": "Usunięto dane książki: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Nie udało się usunąć danych książki: {{title}}",
|
||||
"Purge Book Data": "Usuń wszystkie dane książki",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Spowoduje to trwałe usunięcie książki i wszystkich jej danych, w tym postępu czytania, notatek i zakładek. Tej operacji nie można cofnąć.",
|
||||
"Purge Data": "Usuń wszystkie dane",
|
||||
"Erase the book and all its data, including reading progress": "Usuwa książkę i wszystkie jej dane, w tym postęp czytania",
|
||||
"More Actions": "Więcej akcji",
|
||||
"Sign in and make the book available to share it": "Zaloguj się i pobierz książkę, aby ją udostępnić",
|
||||
"Download the book to export it": "Pobierz książkę, aby ją wyeksportować"
|
||||
}
|
||||
|
||||
@@ -1790,5 +1790,14 @@
|
||||
"Clear Pending": "Limpar pendentes",
|
||||
"Reading statistics": "Estatísticas de leitura",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Tempo de leitura e páginas lidas, sincronizados entre seus dispositivos e o KOReader.",
|
||||
"Auto Sync": "Sincronização automática"
|
||||
"Auto Sync": "Sincronização automática",
|
||||
"Purged book data: {{title}}": "Dados do livro apagados: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Falha ao apagar os dados do livro: {{title}}",
|
||||
"Purge Book Data": "Apagar todos os dados do livro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Isso apaga permanentemente o livro e todos os seus dados, incluindo o progresso de leitura, notas e marcadores. Esta ação não pode ser desfeita.",
|
||||
"Purge Data": "Apagar todos os dados",
|
||||
"Erase the book and all its data, including reading progress": "Apaga o livro e todos os seus dados, incluindo o progresso de leitura",
|
||||
"More Actions": "Mais ações",
|
||||
"Sign in and make the book available to share it": "Faça login e tenha o livro disponível para compartilhá-lo",
|
||||
"Download the book to export it": "Baixe o livro para exportá-lo"
|
||||
}
|
||||
|
||||
@@ -1790,5 +1790,14 @@
|
||||
"Clear Pending": "Limpar Pendentes",
|
||||
"Reading statistics": "Estatísticas de leitura",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Tempo de leitura e páginas lidas, sincronizados entre os seus dispositivos e o KOReader.",
|
||||
"Auto Sync": "Sincronização Automática"
|
||||
"Auto Sync": "Sincronização Automática",
|
||||
"Purged book data: {{title}}": "Dados do livro apagados: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Falha ao apagar os dados do livro: {{title}}",
|
||||
"Purge Book Data": "Apagar todos os dados do livro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Isto apaga permanentemente o livro e todos os seus dados, incluindo o progresso de leitura, notas e marcadores. Esta ação não pode ser desfeita.",
|
||||
"Purge Data": "Apagar todos os dados",
|
||||
"Erase the book and all its data, including reading progress": "Apaga o livro e todos os seus dados, incluindo o progresso de leitura",
|
||||
"More Actions": "Mais ações",
|
||||
"Sign in and make the book available to share it": "Inicie sessão e tenha o livro disponível para o partilhar",
|
||||
"Download the book to export it": "Transfira o livro para o exportar"
|
||||
}
|
||||
|
||||
@@ -1790,5 +1790,14 @@
|
||||
"Clear Pending": "Șterge în așteptare",
|
||||
"Reading statistics": "Statistici de lectură",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Timpul de citire și paginile citite, sincronizate pe dispozitivele tale și KOReader.",
|
||||
"Auto Sync": "Sincronizare automată"
|
||||
"Auto Sync": "Sincronizare automată",
|
||||
"Purged book data: {{title}}": "Datele cărții au fost șterse: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Ștergerea datelor cărții a eșuat: {{title}}",
|
||||
"Purge Book Data": "Șterge toate datele cărții",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Aceasta șterge definitiv cartea și toate datele sale, inclusiv progresul lecturii, notițele și marcajele. Această acțiune nu poate fi anulată.",
|
||||
"Purge Data": "Șterge toate datele",
|
||||
"Erase the book and all its data, including reading progress": "Șterge cartea și toate datele sale, inclusiv progresul lecturii",
|
||||
"More Actions": "Mai multe acțiuni",
|
||||
"Sign in and make the book available to share it": "Conectează-te și fă cartea disponibilă pentru a o partaja",
|
||||
"Download the book to export it": "Descarcă cartea pentru a o exporta"
|
||||
}
|
||||
|
||||
@@ -1823,5 +1823,14 @@
|
||||
"Clear Pending": "Очистить ожидающие",
|
||||
"Reading statistics": "Статистика чтения",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Время чтения и прочитанные страницы, синхронизируются между вашими устройствами и KOReader.",
|
||||
"Auto Sync": "Автосинхронизация"
|
||||
"Auto Sync": "Автосинхронизация",
|
||||
"Purged book data: {{title}}": "Данные книги очищены: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Не удалось очистить данные книги: {{title}}",
|
||||
"Purge Book Data": "Очистить данные книги",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Это навсегда удалит книгу и все её данные, включая прогресс чтения, заметки и закладки. Это действие нельзя отменить.",
|
||||
"Purge Data": "Очистить данные",
|
||||
"Erase the book and all its data, including reading progress": "Удаляет книгу и все её данные, включая прогресс чтения",
|
||||
"More Actions": "Ещё действия",
|
||||
"Sign in and make the book available to share it": "Войдите и сделайте книгу доступной, чтобы поделиться ею",
|
||||
"Download the book to export it": "Скачайте книгу, чтобы экспортировать её"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "බලාපොරොත්තුවේ ඇති ඒවා මකන්න",
|
||||
"Reading statistics": "කියවීමේ සංඛ්යාලේඛන",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "කියවීමේ කාලය සහ කියවූ පිටු, ඔබේ උපාංග සහ KOReader හරහා සමමුහුර්ත වේ.",
|
||||
"Auto Sync": "ස්වයංක්රීය සමමුහුර්තය"
|
||||
"Auto Sync": "ස්වයංක්රීය සමමුහුර්තය",
|
||||
"Purged book data: {{title}}": "පොතේ දත්ත මකා දමන ලදී: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "පොතේ දත්ත මැකීමට අසමත් විය: {{title}}",
|
||||
"Purge Book Data": "පොතේ සියලු දත්ත මකන්න",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "මෙය පොත සහ කියවීමේ ප්රගතිය, සටහන් සහ පිටු සලකුණු ඇතුළුව එහි සියලු දත්ත ස්ථිරවම මකා දමයි. මෙය පෙරළිය නොහැක.",
|
||||
"Purge Data": "සියලු දත්ත මකන්න",
|
||||
"Erase the book and all its data, including reading progress": "කියවීමේ ප්රගතිය ඇතුළුව පොත සහ එහි සියලු දත්ත මකන්න",
|
||||
"More Actions": "තවත් ක්රියා",
|
||||
"Sign in and make the book available to share it": "බෙදා ගැනීමට පුරනය වී පොත ලබා ගත හැකි කරන්න",
|
||||
"Download the book to export it": "අපනයනය කිරීමට පොත බාගන්න"
|
||||
}
|
||||
|
||||
@@ -1823,5 +1823,14 @@
|
||||
"Clear Pending": "Počisti čakajoče",
|
||||
"Reading statistics": "Statistika branja",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Čas branja in prebrane strani, sinhronizirano med vašimi napravami in KOReader.",
|
||||
"Auto Sync": "Samodejna sinhronizacija"
|
||||
"Auto Sync": "Samodejna sinhronizacija",
|
||||
"Purged book data: {{title}}": "Podatki knjige izbrisani: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Podatkov knjige ni bilo mogoče izbrisati: {{title}}",
|
||||
"Purge Book Data": "Izbriši vse podatke knjige",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "S tem trajno izbrišete knjigo in vse njene podatke, vključno z napredkom branja, zapiski in zaznamki. Tega dejanja ni mogoče razveljaviti.",
|
||||
"Purge Data": "Izbriši vse podatke",
|
||||
"Erase the book and all its data, including reading progress": "Izbriše knjigo in vse njene podatke, vključno z napredkom branja",
|
||||
"More Actions": "Več dejanj",
|
||||
"Sign in and make the book available to share it": "Prijavite se in omogočite knjigo za deljenje",
|
||||
"Download the book to export it": "Prenesite knjigo, da jo izvozite"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "Rensa väntande",
|
||||
"Reading statistics": "Lässtatistik",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Lästid och lästa sidor, synkroniserat mellan dina enheter och KOReader.",
|
||||
"Auto Sync": "Automatisk synkronisering"
|
||||
"Auto Sync": "Automatisk synkronisering",
|
||||
"Purged book data: {{title}}": "Bokdata rensad: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Det gick inte att rensa bokdata: {{title}}",
|
||||
"Purge Book Data": "Rensa all bokdata",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Detta raderar permanent boken och all dess data, inklusive läsförlopp, anteckningar och bokmärken. Detta kan inte ångras.",
|
||||
"Purge Data": "Rensa all data",
|
||||
"Erase the book and all its data, including reading progress": "Raderar boken och all data, inklusive läsförlopp",
|
||||
"More Actions": "Fler åtgärder",
|
||||
"Sign in and make the book available to share it": "Logga in och gör boken tillgänglig för att dela den",
|
||||
"Download the book to export it": "Ladda ner boken för att exportera den"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "காத்திருப்பதை அழிக்கவும்",
|
||||
"Reading statistics": "வாசிப்பு புள்ளிவிவரங்கள்",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "வாசிப்பு நேரம் மற்றும் படித்த பக்கங்கள், உங்கள் சாதனங்கள் மற்றும் KOReader இடையே ஒத்திசைக்கப்படும்.",
|
||||
"Auto Sync": "தானியங்கு ஒத்திசைவு"
|
||||
"Auto Sync": "தானியங்கு ஒத்திசைவு",
|
||||
"Purged book data: {{title}}": "புத்தகத் தரவு அழிக்கப்பட்டது: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "புத்தகத் தரவை அழிக்க முடியவில்லை: {{title}}",
|
||||
"Purge Book Data": "புத்தகத்தின் எல்லா தரவையும் அழி",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "இது புத்தகத்தையும் வாசிப்பு முன்னேற்றம், குறிப்புகள் மற்றும் புத்தகக்குறிகள் உள்ளிட்ட அதன் அனைத்து தரவையும் நிரந்தரமாக அழிக்கும். இதை மீட்டெடுக்க முடியாது.",
|
||||
"Purge Data": "எல்லா தரவையும் அழி",
|
||||
"Erase the book and all its data, including reading progress": "வாசிப்பு முன்னேற்றம் உட்பட புத்தகத்தையும் அதன் எல்லா தரவையும் அழிக்கும்",
|
||||
"More Actions": "மேலும் செயல்கள்",
|
||||
"Sign in and make the book available to share it": "பகிர உள்நுழைந்து புத்தகத்தைக் கிடைக்கச் செய்யவும்",
|
||||
"Download the book to export it": "ஏற்றுமதி செய்ய புத்தகத்தைப் பதிவிறக்கவும்"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "ล้างที่รอดำเนินการ",
|
||||
"Reading statistics": "สถิติการอ่าน",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "เวลาในการอ่านและจำนวนหน้าที่อ่าน ซิงค์ข้ามอุปกรณ์ของคุณและ KOReader",
|
||||
"Auto Sync": "ซิงค์อัตโนมัติ"
|
||||
"Auto Sync": "ซิงค์อัตโนมัติ",
|
||||
"Purged book data: {{title}}": "ล้างข้อมูลหนังสือแล้ว: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "ล้างข้อมูลหนังสือไม่สำเร็จ: {{title}}",
|
||||
"Purge Book Data": "ล้างข้อมูลหนังสือทั้งหมด",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "การดำเนินการนี้จะลบหนังสือและข้อมูลทั้งหมดอย่างถาวร รวมถึงความคืบหน้าการอ่าน บันทึก และที่คั่นหนังสือ ไม่สามารถเลิกทำได้",
|
||||
"Purge Data": "ล้างข้อมูลทั้งหมด",
|
||||
"Erase the book and all its data, including reading progress": "ลบหนังสือและข้อมูลทั้งหมด รวมถึงความคืบหน้าการอ่าน",
|
||||
"More Actions": "การทำงานเพิ่มเติม",
|
||||
"Sign in and make the book available to share it": "ลงชื่อเข้าใช้และทำให้หนังสือพร้อมใช้งานเพื่อแชร์",
|
||||
"Download the book to export it": "ดาวน์โหลดหนังสือเพื่อส่งออก"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "Bekleyenleri Temizle",
|
||||
"Reading statistics": "Okuma İstatistikleri",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Okuma süresi ve okunan sayfalar, cihazlarınız ve KOReader arasında senkronize edilir.",
|
||||
"Auto Sync": "Otomatik Senkronizasyon"
|
||||
"Auto Sync": "Otomatik Senkronizasyon",
|
||||
"Purged book data: {{title}}": "Kitap verileri silindi: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Kitap verileri silinemedi: {{title}}",
|
||||
"Purge Book Data": "Tüm kitap verilerini sil",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Bu işlem kitabı ve okuma ilerlemesi, notlar ve yer imleri dahil tüm verilerini kalıcı olarak siler. Bu işlem geri alınamaz.",
|
||||
"Purge Data": "Tüm verileri sil",
|
||||
"Erase the book and all its data, including reading progress": "Kitabı ve okuma ilerlemesi dahil tüm verilerini siler",
|
||||
"More Actions": "Diğer eylemler",
|
||||
"Sign in and make the book available to share it": "Paylaşmak için oturum açın ve kitabı kullanılabilir hale getirin",
|
||||
"Download the book to export it": "Dışa aktarmak için kitabı indirin"
|
||||
}
|
||||
|
||||
@@ -1823,5 +1823,14 @@
|
||||
"Clear Pending": "Очистити очікувані",
|
||||
"Reading statistics": "Статистика читання",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Час читання та прочитані сторінки, синхронізуються між вашими пристроями та KOReader.",
|
||||
"Auto Sync": "Автоматична синхронізація"
|
||||
"Auto Sync": "Автоматична синхронізація",
|
||||
"Purged book data: {{title}}": "Дані книги очищено: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Не вдалося очистити дані книги: {{title}}",
|
||||
"Purge Book Data": "Очистити дані книги",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Це назавжди видалить книгу та всі її дані, зокрема прогрес читання, нотатки та закладки. Цю дію неможливо скасувати.",
|
||||
"Purge Data": "Очистити дані",
|
||||
"Erase the book and all its data, including reading progress": "Видаляє книгу та всі її дані, зокрема прогрес читання",
|
||||
"More Actions": "Більше дій",
|
||||
"Sign in and make the book available to share it": "Увійдіть і зробіть книгу доступною, щоб поділитися нею",
|
||||
"Download the book to export it": "Завантажте книгу, щоб експортувати її"
|
||||
}
|
||||
|
||||
@@ -1757,5 +1757,14 @@
|
||||
"Clear Pending": "Kutilayotganlarni tozalash",
|
||||
"Reading statistics": "Oʻqish statistikasi",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Oʻqish vaqti va oʻqilgan sahifalar, qurilmalaringiz va KOReader oʻrtasida sinxronlanadi.",
|
||||
"Auto Sync": "Avtomatik sinxronlash"
|
||||
"Auto Sync": "Avtomatik sinxronlash",
|
||||
"Purged book data: {{title}}": "Kitob maʼlumotlari oʻchirildi: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Kitob maʼlumotlarini oʻchirib boʻlmadi: {{title}}",
|
||||
"Purge Book Data": "Kitobning barcha maʼlumotlarini oʻchirish",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Bu kitobni va uning barcha maʼlumotlarini, jumladan oʻqish jarayoni, eslatmalar va xatcho‘plarni butunlay oʻchiradi. Buni qaytarib boʻlmaydi.",
|
||||
"Purge Data": "Barcha maʼlumotlarni oʻchirish",
|
||||
"Erase the book and all its data, including reading progress": "Kitobni va uning barcha maʼlumotlarini, jumladan oʻqish jarayonini oʻchiradi",
|
||||
"More Actions": "Qoʻshimcha amallar",
|
||||
"Sign in and make the book available to share it": "Ulashish uchun tizimga kiring va kitobni mavjud qiling",
|
||||
"Download the book to export it": "Eksport qilish uchun kitobni yuklab oling"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "Xóa đang chờ",
|
||||
"Reading statistics": "Thống kê đọc",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "Thời gian đọc và số trang đã đọc, được đồng bộ trên các thiết bị của bạn và KOReader.",
|
||||
"Auto Sync": "Tự động đồng bộ"
|
||||
"Auto Sync": "Tự động đồng bộ",
|
||||
"Purged book data: {{title}}": "Đã xóa dữ liệu sách: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Không thể xóa dữ liệu sách: {{title}}",
|
||||
"Purge Book Data": "Xóa toàn bộ dữ liệu sách",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Thao tác này sẽ xóa vĩnh viễn sách và toàn bộ dữ liệu của nó, bao gồm tiến độ đọc, ghi chú và dấu trang. Không thể hoàn tác.",
|
||||
"Purge Data": "Xóa toàn bộ dữ liệu",
|
||||
"Erase the book and all its data, including reading progress": "Xóa sách và toàn bộ dữ liệu, bao gồm tiến độ đọc",
|
||||
"More Actions": "Thao tác khác",
|
||||
"Sign in and make the book available to share it": "Đăng nhập và tải sách về để chia sẻ",
|
||||
"Download the book to export it": "Tải sách về để xuất ra"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "清除等待中",
|
||||
"Reading statistics": "阅读统计",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "阅读时间和已读页数,在您的设备和 KOReader 之间同步。",
|
||||
"Auto Sync": "自动同步"
|
||||
"Auto Sync": "自动同步",
|
||||
"Purged book data: {{title}}": "已清除书籍数据:{{title}}",
|
||||
"Failed to purge book data: {{title}}": "清除书籍数据失败:{{title}}",
|
||||
"Purge Book Data": "清除书籍数据",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "这将永久删除该书籍及其所有数据,包括阅读进度、笔记和书签。此操作无法撤销。",
|
||||
"Purge Data": "清除数据",
|
||||
"Erase the book and all its data, including reading progress": "删除该书籍及其所有数据,包括阅读进度",
|
||||
"More Actions": "更多操作",
|
||||
"Sign in and make the book available to share it": "登录并使书籍可用后即可分享",
|
||||
"Download the book to export it": "下载书籍后即可导出"
|
||||
}
|
||||
|
||||
@@ -1724,5 +1724,14 @@
|
||||
"Clear Pending": "清除等待中",
|
||||
"Reading statistics": "閱讀統計",
|
||||
"Reading time and pages read, synced across your devices and KOReader.": "閱讀時間與已讀頁數,在您的裝置與 KOReader 之間同步。",
|
||||
"Auto Sync": "自動同步"
|
||||
"Auto Sync": "自動同步",
|
||||
"Purged book data: {{title}}": "已清除書籍資料:{{title}}",
|
||||
"Failed to purge book data: {{title}}": "清除書籍資料失敗:{{title}}",
|
||||
"Purge Book Data": "清除書籍資料",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "這將永久刪除該書籍及其所有資料,包括閱讀進度、筆記和書籤。此操作無法復原。",
|
||||
"Purge Data": "清除資料",
|
||||
"Erase the book and all its data, including reading progress": "刪除該書籍及其所有資料,包括閱讀進度",
|
||||
"More Actions": "更多操作",
|
||||
"Sign in and make the book available to share it": "登入並使書籍可用後即可分享",
|
||||
"Download the book to export it": "下載書籍後即可匯出"
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@ vi.mock('@/context/EnvContext', () => ({
|
||||
useEnv: () => ({ envConfig: { getAppService: async () => appSvc }, appService: appSvc }),
|
||||
}));
|
||||
|
||||
vi.mock('@/context/AuthContext', () => ({
|
||||
useAuth: () => ({ user: { id: 'u1' } }),
|
||||
}));
|
||||
|
||||
vi.mock('@/store/themeStore', () => ({
|
||||
useThemeStore: () => ({ safeAreaInsets: { top: 0, bottom: 0, left: 0, right: 0 } }),
|
||||
}));
|
||||
|
||||
@@ -29,6 +29,10 @@ vi.mock('@/helpers/settings', () => ({
|
||||
saveSysSettings: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/utils/open', () => ({
|
||||
openExternalUrl: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/components/BookCover', () => ({
|
||||
__esModule: true,
|
||||
default: () => null,
|
||||
@@ -103,6 +107,85 @@ describe('BookDetailView delete dropdown layout', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('BookDetailView More menu (Goodreads + Share)', () => {
|
||||
const openMore = (container: HTMLElement) => {
|
||||
const toggle = container.querySelector('button[aria-label="More Actions"]');
|
||||
expect(toggle).toBeTruthy();
|
||||
fireEvent.click(toggle!);
|
||||
};
|
||||
|
||||
it('folds Goodreads and Share into the hamburger menu', () => {
|
||||
const { container, getByText } = renderView({ onShare: vi.fn(), shareEnabled: true });
|
||||
// Goodreads is no longer a standalone icon button outside the menu.
|
||||
expect(container.querySelector('button[aria-label="More Actions"]')).toBeTruthy();
|
||||
openMore(container);
|
||||
expect(getByText('Search on Goodreads')).toBeTruthy();
|
||||
expect(getByText('Share Book')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('enables Share and calls onShare when the book is shareable', () => {
|
||||
const onShare = vi.fn();
|
||||
const { container, getByText } = renderView({ onShare, shareEnabled: true });
|
||||
openMore(container);
|
||||
const shareButton = getByText('Share Book').closest('button');
|
||||
expect(shareButton).toBeTruthy();
|
||||
expect(shareButton!.disabled).toBe(false);
|
||||
fireEvent.click(shareButton!);
|
||||
expect(onShare).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('disables Share when not shareable (logged out or no local file)', () => {
|
||||
const onShare = vi.fn();
|
||||
const { container, getByText } = renderView({ onShare, shareEnabled: false });
|
||||
openMore(container);
|
||||
const shareButton = getByText('Share Book').closest('button');
|
||||
expect(shareButton!.disabled).toBe(true);
|
||||
fireEvent.click(shareButton!);
|
||||
expect(onShare).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps Export in the More menu and calls onExport when the file exists', () => {
|
||||
const onExport = vi.fn();
|
||||
const { container, getByText } = renderView({ onExport, fileSize: 1024 });
|
||||
openMore(container);
|
||||
const exportButton = getByText('Export Book').closest('button');
|
||||
expect(exportButton).toBeTruthy();
|
||||
expect(exportButton!.disabled).toBe(false);
|
||||
fireEvent.click(exportButton!);
|
||||
expect(onExport).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('disables Export when the book has no local file', () => {
|
||||
const onExport = vi.fn();
|
||||
const { container, getByText } = renderView({ onExport, fileSize: null });
|
||||
openMore(container);
|
||||
const exportButton = getByText('Export Book').closest('button');
|
||||
expect(exportButton!.disabled).toBe(true);
|
||||
fireEvent.click(exportButton!);
|
||||
expect(onExport).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('BookDetailView Purge Data action', () => {
|
||||
it('offers Purge Data in the delete dropdown and calls onPurge', () => {
|
||||
const onPurge = vi.fn();
|
||||
const { container, getByText } = renderView({ onPurge });
|
||||
const toggle = container.querySelector('button[aria-label="Delete Book Options"]');
|
||||
fireEvent.click(toggle!);
|
||||
const purgeButton = getByText('Purge Data').closest('button');
|
||||
expect(purgeButton).toBeTruthy();
|
||||
fireEvent.click(purgeButton!);
|
||||
expect(onPurge).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('omits Purge Data when onPurge is not provided', () => {
|
||||
const { container, queryByText } = renderView();
|
||||
const toggle = container.querySelector('button[aria-label="Delete Book Options"]');
|
||||
fireEvent.click(toggle!);
|
||||
expect(queryByText('Purge Data')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('BookDetailView file path row', () => {
|
||||
// book.filePath is only set for in-place imports (and OS-handed paths like
|
||||
// Android "Open with Readest"). Hash-copy imports leave it undefined, so
|
||||
|
||||
@@ -176,6 +176,73 @@ describe('cloudService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// Purge is the "Cloud & Device" delete PLUS a full wipe of the
|
||||
// app-generated Books/<hash>/ directory (config.json reading progress/notes,
|
||||
// nav.json, cover.png) that the other deletes leave behind (issue #4615).
|
||||
// The local-file side lives here; the tombstone + queued cloud deletion are
|
||||
// owned by the page's handleBookDelete, exactly like the 'both'/'local'
|
||||
// split, so this branch must NOT touch deletedAt or the cloud.
|
||||
describe('purge delete action', () => {
|
||||
test('removes the entire Books/<hash>/ directory', async () => {
|
||||
const book = createMockBook();
|
||||
await deleteBook(mockFs, book, 'purge');
|
||||
|
||||
expect(mockFs.removeDir).toHaveBeenCalledWith(book.hash, 'Books', true);
|
||||
});
|
||||
|
||||
test('does not remove the managed book file individually (the dir wipe covers it)', async () => {
|
||||
const book = createMockBook();
|
||||
await deleteBook(mockFs, book, 'purge');
|
||||
|
||||
// The whole directory is removed in one shot; no per-file removeFile.
|
||||
expect(mockFs.removeFile).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('clears downloadedAt but leaves deletedAt for the caller (mirrors local)', async () => {
|
||||
const book = createMockBook({ downloadedAt: 12345, deletedAt: null });
|
||||
await deleteBook(mockFs, book, 'purge');
|
||||
|
||||
expect(book.downloadedAt).toBeNull();
|
||||
expect(book.deletedAt).toBeNull();
|
||||
});
|
||||
|
||||
test('does not delete cloud files (the page queues the cloud deletion)', async () => {
|
||||
const { deleteFile: deleteCloudFile } = await import('@/libs/storage');
|
||||
const book = createMockBook({ uploadedAt: 1000 });
|
||||
await deleteBook(mockFs, book, 'purge');
|
||||
|
||||
expect(deleteCloudFile).not.toHaveBeenCalled();
|
||||
// uploadedAt is left intact for the queued cloud-delete transfer to clear.
|
||||
expect(book.uploadedAt).toBe(1000);
|
||||
});
|
||||
|
||||
test('removes the in-place source file and the sidecar dir for in-place books', async () => {
|
||||
const book = createMockBook({ filePath: '/Users/me/Library/sample.epub' });
|
||||
vi.mocked(mockFs.exists).mockImplementation(async (path, base) => {
|
||||
if (base === 'None' && path === book.filePath) return true;
|
||||
if (base === 'Books' && path === book.hash) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
await deleteBook(mockFs, book, 'purge');
|
||||
|
||||
// External source file (outside Books/<hash>/) is removed...
|
||||
expect(mockFs.removeFile).toHaveBeenCalledWith('/Users/me/Library/sample.epub', 'None');
|
||||
// ...and the metadata sidecar directory is wiped too.
|
||||
expect(mockFs.removeDir).toHaveBeenCalledWith(book.hash, 'Books', true);
|
||||
});
|
||||
|
||||
test('does not throw when the directory does not exist', async () => {
|
||||
vi.mocked(mockFs.exists).mockResolvedValue(false);
|
||||
const book = createMockBook({ downloadedAt: 12345 });
|
||||
|
||||
await deleteBook(mockFs, book, 'purge');
|
||||
|
||||
expect(mockFs.removeDir).not.toHaveBeenCalled();
|
||||
expect(book.downloadedAt).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('cloud delete action', () => {
|
||||
test('does not delete local files', async () => {
|
||||
const book = createMockBook({ uploadedAt: 1000 });
|
||||
|
||||
@@ -877,18 +877,22 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
|
||||
both: _('Book deleted: {{title}}', { title: book.title }),
|
||||
cloud: _('Deleted cloud backup of the book: {{title}}', { title: book.title }),
|
||||
local: _('Deleted local copy of the book: {{title}}', { title: book.title }),
|
||||
purge: _('Purged book data: {{title}}', { title: book.title }),
|
||||
};
|
||||
const deletionFailMessages = {
|
||||
both: _('Failed to delete book: {{title}}', { title: book.title }),
|
||||
cloud: _('Failed to delete cloud backup of the book: {{title}}', { title: book.title }),
|
||||
local: _('Failed to delete local copy of the book: {{title}}', { title: book.title }),
|
||||
purge: _('Failed to purge book data: {{title}}', { title: book.title }),
|
||||
};
|
||||
|
||||
try {
|
||||
// Handle local deletion immediately
|
||||
if (deleteAction === 'local' || deleteAction === 'both') {
|
||||
await appService?.deleteBook(book, 'local');
|
||||
if (deleteAction === 'both') {
|
||||
// Handle local deletion immediately. Purge mirrors 'both' (tombstone +
|
||||
// queued cloud delete) but hands 'purge' to deleteBook, which also wipes
|
||||
// the entire Books/<hash>/ folder (config/nav/cover) — issue #4615.
|
||||
if (deleteAction === 'local' || deleteAction === 'both' || deleteAction === 'purge') {
|
||||
await appService?.deleteBook(book, deleteAction === 'purge' ? 'purge' : 'local');
|
||||
if (deleteAction === 'both' || deleteAction === 'purge') {
|
||||
book.deletedAt = Date.now();
|
||||
book.downloadedAt = null;
|
||||
book.coverDownloadedAt = null;
|
||||
@@ -899,7 +903,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
|
||||
}
|
||||
|
||||
// Queue cloud deletion
|
||||
if (deleteAction === 'cloud' || deleteAction === 'both') {
|
||||
if (deleteAction === 'cloud' || deleteAction === 'both' || deleteAction === 'purge') {
|
||||
const transferId = transferManager.queueDelete(book, 1, true);
|
||||
if (!transferId) {
|
||||
throw new Error('Failed to queue cloud deletion');
|
||||
@@ -1468,6 +1472,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
|
||||
handleBookDelete={handleBookDelete('both')}
|
||||
handleBookDeleteCloudBackup={handleBookDelete('cloud')}
|
||||
handleBookDeleteLocalCopy={handleBookDelete('local')}
|
||||
handleBookPurge={handleBookDelete('purge')}
|
||||
handleBookMetadataUpdate={handleUpdateMetadata}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Book } from '@/types/book';
|
||||
import { getBookWithUpdatedMetadata } from '@/utils/book';
|
||||
import { BookMetadata } from '@/libs/document';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useThemeStore } from '@/store/themeStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useMetadataEdit } from './useMetadataEdit';
|
||||
@@ -27,6 +28,7 @@ interface BookDetailModalProps {
|
||||
handleBookDelete?: (book: Book) => void;
|
||||
handleBookDeleteCloudBackup?: (book: Book) => void;
|
||||
handleBookDeleteLocalCopy?: (book: Book) => void;
|
||||
handleBookPurge?: (book: Book) => void;
|
||||
handleBookMetadataUpdate?: (book: Book, updatedMetadata: BookMetadata) => void;
|
||||
}
|
||||
|
||||
@@ -45,10 +47,12 @@ const BookDetailModal: React.FC<BookDetailModalProps> = ({
|
||||
handleBookDelete,
|
||||
handleBookDeleteCloudBackup,
|
||||
handleBookDeleteLocalCopy,
|
||||
handleBookPurge,
|
||||
handleBookMetadataUpdate,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
const { envConfig, appService } = useEnv();
|
||||
const { user } = useAuth();
|
||||
const { safeAreaInsets } = useThemeStore();
|
||||
const [activeDeleteAction, setActiveDeleteAction] = useState<DeleteAction | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -95,6 +99,13 @@ const BookDetailModal: React.FC<BookDetailModalProps> = ({
|
||||
message: _('Are you sure to delete the local copy of the selected book?'),
|
||||
handler: handleBookDeleteLocalCopy,
|
||||
},
|
||||
purge: {
|
||||
title: _('Purge Book Data'),
|
||||
message: _(
|
||||
'This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.',
|
||||
),
|
||||
handler: handleBookPurge,
|
||||
},
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -168,19 +179,14 @@ const BookDetailModal: React.FC<BookDetailModalProps> = ({
|
||||
const handleDelete = () => handleDeleteAction('both');
|
||||
const handleDeleteCloudBackup = () => handleDeleteAction('cloud');
|
||||
const handleDeleteLocalCopy = () => handleDeleteAction('local');
|
||||
const handlePurge = () => handleDeleteAction('purge');
|
||||
|
||||
const handleRedownload = async () => {
|
||||
const handleShare = () => {
|
||||
// Close this modal first, then hand off to the share dialog hosted by
|
||||
// Bookshelf (it owns the login gate + ShareBookDialog). Mirrors how the
|
||||
// bookshelf context menu dispatches the same event.
|
||||
handleClose();
|
||||
if (handleBookDownload) {
|
||||
handleBookDownload(book, { redownload: true, queued: false });
|
||||
}
|
||||
};
|
||||
|
||||
const handleReupload = async () => {
|
||||
handleClose();
|
||||
if (handleBookUpload) {
|
||||
handleBookUpload(book);
|
||||
}
|
||||
eventDispatcher.dispatch('show-share-dialog', { book });
|
||||
};
|
||||
|
||||
const handleBookExport = async () => {
|
||||
@@ -197,6 +203,25 @@ const BookDetailModal: React.FC<BookDetailModalProps> = ({
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const handleRedownload = async () => {
|
||||
handleClose();
|
||||
if (handleBookDownload) {
|
||||
handleBookDownload(book, { redownload: true, queued: false });
|
||||
}
|
||||
};
|
||||
|
||||
const handleReupload = async () => {
|
||||
handleClose();
|
||||
if (handleBookUpload) {
|
||||
handleBookUpload(book);
|
||||
}
|
||||
};
|
||||
|
||||
// Sharing uploads the book to the Readest backend and mints a public link, so
|
||||
// it needs a signed-in user and a resolvable on-disk file. `fileSize` is only
|
||||
// non-null when getBookFileSize could actually open the local file.
|
||||
const shareEnabled = !!user && fileSize !== null;
|
||||
|
||||
const currentDeleteConfig = activeDeleteAction ? deleteConfigs[activeDeleteAction] : null;
|
||||
|
||||
return (
|
||||
@@ -235,14 +260,17 @@ const BookDetailModal: React.FC<BookDetailModalProps> = ({
|
||||
book={displayBook}
|
||||
metadata={bookMeta}
|
||||
fileSize={fileSize}
|
||||
shareEnabled={shareEnabled}
|
||||
onEdit={handleBookMetadataUpdate ? handleEditMetadata : undefined}
|
||||
onDelete={handleBookDelete ? handleDelete : undefined}
|
||||
onDeleteCloudBackup={
|
||||
handleBookDeleteCloudBackup ? handleDeleteCloudBackup : undefined
|
||||
}
|
||||
onDeleteLocalCopy={handleBookDeleteLocalCopy ? handleDeleteLocalCopy : undefined}
|
||||
onPurge={handleBookPurge ? handlePurge : undefined}
|
||||
onDownload={handleBookDownload ? handleRedownload : undefined}
|
||||
onUpload={handleBookUpload ? handleReupload : undefined}
|
||||
onShare={handleShare}
|
||||
onExport={handleBookExport}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -5,11 +5,10 @@ import {
|
||||
MdOutlineCloudUpload,
|
||||
MdOutlineDelete,
|
||||
MdOutlineEdit,
|
||||
MdSaveAlt,
|
||||
MdMenu,
|
||||
MdExpandMore,
|
||||
MdExpandLess,
|
||||
} from 'react-icons/md';
|
||||
import { FaGoodreads } from 'react-icons/fa';
|
||||
|
||||
import { Book } from '@/types/book';
|
||||
import { BookMetadata } from '@/libs/document';
|
||||
@@ -35,12 +34,15 @@ interface BookDetailViewProps {
|
||||
book: Book;
|
||||
metadata: BookMetadata | null;
|
||||
fileSize: number | null;
|
||||
shareEnabled?: boolean;
|
||||
onEdit?: () => void;
|
||||
onDelete?: () => void;
|
||||
onDeleteCloudBackup?: () => void;
|
||||
onDeleteLocalCopy?: () => void;
|
||||
onPurge?: () => void;
|
||||
onDownload?: () => void;
|
||||
onUpload?: () => void;
|
||||
onShare?: () => void;
|
||||
onExport?: () => void;
|
||||
}
|
||||
|
||||
@@ -48,18 +50,25 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
book,
|
||||
metadata,
|
||||
fileSize,
|
||||
shareEnabled,
|
||||
onEdit,
|
||||
onDelete,
|
||||
onDeleteCloudBackup,
|
||||
onDeleteLocalCopy,
|
||||
onPurge,
|
||||
onDownload,
|
||||
onUpload,
|
||||
onShare,
|
||||
onExport,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
const { envConfig } = useEnv();
|
||||
const { settings } = useSettingsStore();
|
||||
|
||||
// Export and Share both read the book file off disk; `fileSize` is only
|
||||
// non-null when getBookFileSize could actually open the local copy.
|
||||
const hasLocalFile = fileSize !== null;
|
||||
|
||||
const toggleSeriesCollapse = () => {
|
||||
saveSysSettings(envConfig, 'metadataSeriesCollapsed', !settings.metadataSeriesCollapsed);
|
||||
};
|
||||
@@ -101,12 +110,16 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
<MdOutlineEdit className='hover:fill-blue-500' />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => openExternalUrl(getGoodreadsSearchUrl(getBookGoodreadsQuery(book)))}
|
||||
title={_('Search on Goodreads')}
|
||||
>
|
||||
<FaGoodreads className='fill-base-content' />
|
||||
</button>
|
||||
{book.uploadedAt && onDownload && (
|
||||
<button onClick={onDownload} title={_('Download from Cloud')}>
|
||||
<MdOutlineCloudDownload className='fill-base-content' />
|
||||
</button>
|
||||
)}
|
||||
{book.downloadedAt && onUpload && (
|
||||
<button onClick={onUpload} title={_('Upload to Cloud')}>
|
||||
<MdOutlineCloudUpload className='fill-base-content' />
|
||||
</button>
|
||||
)}
|
||||
{onDelete && (
|
||||
<Dropdown
|
||||
label={_('Delete Book Options')}
|
||||
@@ -140,24 +153,65 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
onClick={onDeleteLocalCopy}
|
||||
disabled={!book.downloadedAt}
|
||||
/>
|
||||
{onPurge && (
|
||||
<MenuItem
|
||||
noIcon
|
||||
transient
|
||||
label={_('Purge Data')}
|
||||
labelClass='text-red-500'
|
||||
tooltip={_('Erase the book and all its data, including reading progress')}
|
||||
onClick={onPurge}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Dropdown>
|
||||
)}
|
||||
{book.uploadedAt && onDownload && (
|
||||
<button onClick={onDownload} title={_('Download from Cloud')}>
|
||||
<MdOutlineCloudDownload className='fill-base-content' />
|
||||
</button>
|
||||
)}
|
||||
{book.downloadedAt && onUpload && (
|
||||
<button onClick={onUpload} title={_('Upload to Cloud')}>
|
||||
<MdOutlineCloudUpload className='fill-base-content' />
|
||||
</button>
|
||||
)}
|
||||
{book.downloadedAt && onExport && (
|
||||
<button onClick={onExport} title={_('Export Book')}>
|
||||
<MdSaveAlt className='fill-base-content' />
|
||||
</button>
|
||||
)}
|
||||
<Dropdown
|
||||
label={_('More Actions')}
|
||||
className='dropdown-bottom dropdown-center flex justify-center'
|
||||
buttonClassName='btn btn-ghost h-8 min-h-8 w-8 p-0'
|
||||
toggleButton={<MdMenu className='fill-base-content' />}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
'more-menu dropdown-content no-triangle !relative',
|
||||
'border-base-300 !bg-base-200 z-20 mt-1 max-w-[90vw] shadow-2xl',
|
||||
)}
|
||||
>
|
||||
<MenuItem
|
||||
noIcon
|
||||
transient
|
||||
label={_('Search on Goodreads')}
|
||||
onClick={() =>
|
||||
openExternalUrl(getGoodreadsSearchUrl(getBookGoodreadsQuery(book)))
|
||||
}
|
||||
/>
|
||||
{onShare && (
|
||||
<MenuItem
|
||||
noIcon
|
||||
transient
|
||||
label={_('Share Book')}
|
||||
disabled={!shareEnabled}
|
||||
tooltip={
|
||||
shareEnabled
|
||||
? undefined
|
||||
: _('Sign in and make the book available to share it')
|
||||
}
|
||||
onClick={onShare}
|
||||
/>
|
||||
)}
|
||||
{onExport && (
|
||||
<MenuItem
|
||||
noIcon
|
||||
transient
|
||||
label={_('Export Book')}
|
||||
disabled={!hasLocalFile}
|
||||
tooltip={hasLocalFile ? undefined : _('Download the book to export it')}
|
||||
onClick={onExport}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function deleteBook(
|
||||
book: Book,
|
||||
deleteAction: DeleteAction,
|
||||
): Promise<void> {
|
||||
if (deleteAction === 'local' || deleteAction === 'both') {
|
||||
if (deleteAction === 'local' || deleteAction === 'both' || deleteAction === 'purge') {
|
||||
const source = await resolveBookContentSource(fs, book);
|
||||
if (source.kind === 'external') {
|
||||
try {
|
||||
@@ -36,16 +36,32 @@ export async function deleteBook(
|
||||
// the metadata-side bookkeeping that follows.
|
||||
console.log('Failed to remove in-place source file:', error);
|
||||
}
|
||||
} else if (source.kind === 'managed') {
|
||||
} else if (source.kind === 'managed' && deleteAction !== 'purge') {
|
||||
// Purge wipes the whole directory below, so skip the per-file removal.
|
||||
if (await fs.exists(source.path, source.base)) {
|
||||
await fs.removeFile(source.path, source.base);
|
||||
}
|
||||
}
|
||||
|
||||
// Purge erases the entire app-generated Books/<hash>/ directory — the
|
||||
// managed book file, cover.png, and (the reason for issue #4615)
|
||||
// config.json (reading progress, notes, bookmarks) + nav.json that the
|
||||
// other delete actions leave behind. For in-place books the external
|
||||
// source file was already removed above; this clears the sidecar dir.
|
||||
if (deleteAction === 'purge') {
|
||||
const dir = getDir(book);
|
||||
if (await fs.exists(dir, 'Books')) {
|
||||
await fs.removeDir(dir, 'Books', true);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteAction === 'both' && (await fs.exists(getCoverFilename(book), 'Books'))) {
|
||||
await fs.removeFile(getCoverFilename(book), 'Books');
|
||||
}
|
||||
if (deleteAction === 'local') {
|
||||
if (deleteAction === 'local' || deleteAction === 'purge') {
|
||||
// Mirror 'local': mark not-downloaded but leave the tombstone (deletedAt)
|
||||
// to the caller. The page's handleBookDelete sets deletedAt and queues the
|
||||
// cloud deletion for purge, exactly as it does for the 'both' action.
|
||||
book.downloadedAt = null;
|
||||
} else {
|
||||
book.deletedAt = Date.now();
|
||||
|
||||
@@ -15,7 +15,7 @@ export type AppPlatform = 'web' | 'tauri' | 'node';
|
||||
export type OsPlatform = 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'unknown';
|
||||
// biome-ignore format: keep the union members compact on a single line
|
||||
export type BaseDir = | 'Books' | 'Settings' | 'Data' | 'Fonts' | 'Images' | 'Dictionaries' | 'Log' | 'Cache' | 'Temp' | 'None';
|
||||
export type DeleteAction = 'cloud' | 'local' | 'both';
|
||||
export type DeleteAction = 'cloud' | 'local' | 'both' | 'purge';
|
||||
export type SelectDirectoryMode = 'read' | 'write';
|
||||
export type DistChannel = 'readest' | 'playstore' | 'appstore' | 'unknown';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user