diff --git a/apps/readest-app/package.json b/apps/readest-app/package.json index cd2810ea..7b69cd9c 100644 --- a/apps/readest-app/package.json +++ b/apps/readest-app/package.json @@ -74,6 +74,7 @@ "react-i18next": "^15.2.0", "react-icons": "^5.4.0", "react-responsive": "^10.0.0", + "semver": "^7.7.1", "tinycolor2": "^1.6.0", "zustand": "5.0.1" }, @@ -86,6 +87,7 @@ "@types/react": "18.3.12", "@types/react-color": "^3.0.13", "@types/react-dom": "18.3.1", + "@types/semver": "^7.7.0", "@types/tinycolor2": "^1.4.6", "autoprefixer": "^10.4.20", "cpx2": "^8.0.0", diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index 6ec0673b..3277c652 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "تطبيق على جميع الكتب", "Apply to This Book": "تطبيق على هذا الكتاب", "Unable to fetch the translation. Try again later.": "تعذر جلب الترجمة. حاول مرة أخرى لاحقًا.", - "Update Now!": "قم بالتحديث الآن!", - "Update": "تحديث", "Check Update": "التحقق من التحديث", "Already the latest version": "الإصدار الحالي هو الإصدار الأحدث بالفعل", "Book Details": "تفاصيل الكتاب", @@ -276,5 +274,12 @@ "CJK Font": "خط CJK", "Clear Search": "مسح البحث", "Header & Footer": "الرأس والتذييل", - "Apply also in Scrolled Mode": "تطبيق أيضًا في وضع التمرير" + "Apply also in Scrolled Mode": "تطبيق أيضًا في وضع التمرير", + "A new version of Readest is Available!": "إصدار جديد من ريديست متاح!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "إصدار ريديست {{newVersion}} متاح (الإصدار المثبت {{currentVersion}}).", + "Download and install now?": "هل ترغب في تنزيل وتثبيت الآن؟", + "Downloading {{downloaded}} of {{contentLength}}": "جارٍ تنزيل {{downloaded}} من {{contentLength}}", + "Download finished": "اكتمل التنزيل", + "DOWNLOAD & INSTALL": "تنزيل وتثبيت", + "Changelog:": "سجل التغييرات:" } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 6f2dfc5b..e59d6811 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Auf alle Bücher anwenden", "Apply to This Book": "Auf dieses Buch anwenden", "Unable to fetch the translation. Try again later.": "Übersetzung konnte nicht abgerufen werden. Versuchen Sie es später erneut.", - "Update Now!": "Jetzt aktualisieren!", - "Update": "Aktualisieren", "Check Update": "Aktualisierung prüfen", "Already the latest version": "Bereits die neueste Version", "Book Details": "Buchdetails", @@ -276,5 +274,12 @@ "CJK Font": "CJK-Schriftart", "Clear Search": "Suche löschen", "Header & Footer": "Kopf- & Fußzeile", - "Apply also in Scrolled Mode": "Auch im Scroll-Modus anwenden" + "Apply also in Scrolled Mode": "Auch im Scroll-Modus anwenden", + "A new version of Readest is Available!": "Eine neue Version von Readest ist verfügbar!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} ist verfügbar (installierte Version {{currentVersion}}).", + "Download and install now?": "Jetzt herunterladen und installieren?", + "Downloading {{downloaded}} of {{contentLength}}": "Herunterladen {{downloaded}} von {{contentLength}}", + "Download finished": "Download abgeschlossen", + "DOWNLOAD & INSTALL": "HERUNTERLADEN & INSTALLIEREN", + "Changelog:": "Änderungsprotokoll:" } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index edb2d1d5..81de62ca 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Εφαρμογή σε όλα τα βιβλία", "Apply to This Book": "Εφαρμογή σε αυτό το βιβλίο", "Unable to fetch the translation. Try again later.": "Αδυναμία λήψης της μετάφρασης. Δοκιμάστε ξανά αργότερα.", - "Update Now!": "Ενημέρωση τώρα!", - "Update": "Ενημέρωση", "Check Update": "Έλεγχος ενημέρωσης", "Already the latest version": "Ήδη η τελευταία έκδοση", "Book Details": "Λεπτομέρειες βιβλίου", @@ -276,5 +274,12 @@ "CJK Font": "Γραμματοσειρά CJK", "Clear Search": "Καθαρισμός αναζήτησης", "Header & Footer": "Κεφαλίδα & Υποσέλιδο", - "Apply also in Scrolled Mode": "Εφαρμογή και σε λειτουργία κύλισης" + "Apply also in Scrolled Mode": "Εφαρμογή και σε λειτουργία κύλισης", + "A new version of Readest is Available!": "Μια νέα έκδοση του Readest είναι διαθέσιμη!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Η έκδοση Readest {{newVersion}} είναι διαθέσιμη (έκδοση που είναι εγκατεστημένη {{currentVersion}}).", + "Download and install now?": "Θέλετε να την κατεβάσετε και να την εγκαταστήσετε τώρα;", + "Downloading {{downloaded}} of {{contentLength}}": "Κατεβάζω {{downloaded}} από {{contentLength}}", + "Download finished": "Η λήψη ολοκληρώθηκε", + "DOWNLOAD & INSTALL": "ΛΗΨΗ & ΕΓΚΑΤΑΣΤΑΣΗ", + "Changelog:": "Αλλαγές:" } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index 091baef8..9dedbbb8 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Aplicar a todos los libros", "Apply to This Book": "Aplicar a este libro", "Unable to fetch the translation. Try again later.": "No se puede obtener la traducción. Inténtalo de nuevo más tarde.", - "Update Now!": "¡Actualizar ahora!", - "Update": "Actualizar", "Check Update": "Comprobar actualización", "Already the latest version": "Ya es la última versión", "Book Details": "Detalles del libro", @@ -276,5 +274,12 @@ "CJK Font": "Fuente CJK", "Clear Search": "Limpiar búsqueda", "Header & Footer": "Encabezado y pie de página", - "Apply also in Scrolled Mode": "Aplicar también en modo desplazamiento" + "Apply also in Scrolled Mode": "Aplicar también en modo desplazamiento", + "A new version of Readest is Available!": "¡Una nueva versión de Readest está disponible!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} está disponible (versión instalada {{currentVersion}}).", + "Download and install now?": "Descargar e instalar ahora?", + "Downloading {{downloaded}} of {{contentLength}}": "Descargando {{downloaded}} de {{contentLength}}", + "Download finished": "Descarga finalizada", + "DOWNLOAD & INSTALL": "DESCARGAR E INSTALAR", + "Changelog:": "Notas de la versión:" } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index ed979381..a550569b 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Appliquer à tous les livres", "Apply to This Book": "Appliquer à ce livre", "Unable to fetch the translation. Try again later.": "Impossible de récupérer la traduction. Réessayez plus tard.", - "Update Now!": "Mettre à jour maintenant !", - "Update": "Mettre à jour", "Check Update": "Vérifier la mise à jour", "Already the latest version": "Déjà la dernière version", "Book Details": "Détails du livre", @@ -276,5 +274,12 @@ "CJK Font": "Police CJK", "Clear Search": "Effacer la recherche", "Header & Footer": "En-tête et pied de page", - "Apply also in Scrolled Mode": "Appliquer également en mode défilement" + "Apply also in Scrolled Mode": "Appliquer également en mode défilement", + "A new version of Readest is Available!": "Avis de mise à jour", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} est disponible (version installée {{currentVersion}}).", + "Download and install now?": "Télécharger et installer maintenant ?", + "Downloading {{downloaded}} of {{contentLength}}": "Téléchargement {{downloaded}} sur {{contentLength}}", + "Download finished": "Téléchargement terminé", + "DOWNLOAD & INSTALL": "TÉLÉCHARGER ET INSTALLER", + "Changelog:": "Journal des modifications :" } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index 34c167d6..1bcafc45 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "सभी पुस्तकों पर लागू करें", "Apply to This Book": "इस पुस्तक पर लागू करें", "Unable to fetch the translation. Try again later.": "अनुवाद प्राप्त करने में असमर्थ। बाद में पुनः प्रयास करें।", - "Update Now!": "अभी अपडेट करें!", - "Update": "अपडेट करें", "Check Update": "अपडेट जांचें", "Already the latest version": "पहले से ही नवीनतम संस्करण", "Book Details": "पुस्तक विवरण", @@ -276,5 +274,12 @@ "CJK Font": "CJK फ़ॉन्ट", "Clear Search": "खोज साफ करें", "Header & Footer": "हेडर और फ़ुटर", - "Apply also in Scrolled Mode": "स्क्रॉल मोड में भी लागू करें" + "Apply also in Scrolled Mode": "स्क्रॉल मोड में भी लागू करें", + "A new version of Readest is Available!": "Readest का एक नया संस्करण उपलब्ध है!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} उपलब्ध है (स्थापित संस्करण {{currentVersion}})।", + "Download and install now?": "अब डाउनलोड और इंस्टॉल करें?", + "Downloading {{downloaded}} of {{contentLength}}": "डाउनलोड कर रहा है {{downloaded}} का {{contentLength}}", + "Download finished": "डाउनलोड पूरा हुआ", + "DOWNLOAD & INSTALL": "डाउनलोड और इंस्टॉल करें", + "Changelog:": "चेंजलॉग:" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index ca68a7e0..167c54b4 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Terapkan ke semua buku", "Apply to This Book": "Terapkan ke buku ini", "Unable to fetch the translation. Try again later.": "Tidak dapat mengambil terjemahan. Coba lagi nanti.", - "Update Now!": "Perbarui Sekarang!", - "Update": "Perbarui", "Check Update": "Periksa pembaruan", "Already the latest version": "Sudah versi terbaru", "Book Details": "Detail Buku", @@ -276,5 +274,12 @@ "CJK Font": "Font CJK", "Clear Search": "Hapus Pencarian", "Header & Footer": "Header & Footer", - "Apply also in Scrolled Mode": "Terapkan juga di Mode Gulir" + "Apply also in Scrolled Mode": "Terapkan juga di Mode Gulir", + "A new version of Readest is Available!": "Versi baru Readest Tersedia!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} tersedia (versi terinstal {{currentVersion}}).", + "Download and install now?": "Unduh dan instal sekarang?", + "Downloading {{downloaded}} of {{contentLength}}": "Mengunduh {{downloaded}} dari {{contentLength}}", + "Download finished": "Unduhan selesai", + "DOWNLOAD & INSTALL": "UNDUH & INSTAL", + "Changelog:": "Catatan Perubahan:" } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index 7787557f..e4a0e171 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Applica a tutti i libri", "Apply to This Book": "Applica a questo libro", "Unable to fetch the translation. Try again later.": "Impossibile recuperare la traduzione. Riprova più tardi.", - "Update Now!": "Aggiorna ora!", - "Update": "Aggiorna", "Check Update": "Controlla aggiornamento", "Already the latest version": "Già l'ultima versione", "Book Details": "Dettagli libro", @@ -276,5 +274,12 @@ "CJK Font": "Font CJK", "Clear Search": "Cancella ricerca", "Header & Footer": "Intestazione e piè di pagina", - "Apply also in Scrolled Mode": "Applica anche in modalità scorrimento" + "Apply also in Scrolled Mode": "Applica anche in modalità scorrimento", + "A new version of Readest is Available!": "È disponibile una nuova versione di Readest!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} è disponibile (versione installata {{currentVersion}}).", + "Download and install now?": "Scarica e installa ora?", + "Downloading {{downloaded}} of {{contentLength}}": "Scaricando {{downloaded}} di {{contentLength}}", + "Download finished": "Download completato", + "DOWNLOAD & INSTALL": "SCARICA E INSTALLA", + "Changelog:": "Note di rilascio:" } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index 8b3492cb..f9650329 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "すべての書籍に適用", "Apply to This Book": "この書籍に適用", "Unable to fetch the translation. Try again later.": "翻訳を取得できません。後で再試行してください。", - "Update Now!": "今すぐ更新!", - "Update": "更新", "Check Update": "更新を確認", "Already the latest version": "すでに最新バージョン", "Book Details": "書籍の詳細", @@ -276,5 +274,12 @@ "CJK Font": "CJKフォント", "Clear Search": "検索をクリア", "Header & Footer": "ヘッダーとフッター", - "Apply also in Scrolled Mode": "スクロールモードでも適用" + "Apply also in Scrolled Mode": "スクロールモードでも適用", + "A new version of Readest is Available!": "新しいバージョンのReadestが利用可能です!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}}が利用可能です(インストールされたバージョン{{currentVersion}})。", + "Download and install now?": "今すぐダウンロードしてインストールしますか?", + "Downloading {{downloaded}} of {{contentLength}}": "ダウンロード中 {{downloaded}} / {{contentLength}}", + "Download finished": "ダウンロード完了", + "DOWNLOAD & INSTALL": "更新", + "Changelog:": "変更ログ:" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index 881cf94d..f438dab1 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "모든 책에 적용", "Apply to This Book": "이 책에 적용", "Unable to fetch the translation. Try again later.": "번역을 가져올 수 없습니다. 나중에 다시 시도하세요.", - "Update Now!": "지금 업데이트!", - "Update": "업데이트", "Check Update": "업데이트 확인", "Already the latest version": "이미 최신 버전", "Book Details": "책 세부 정보", @@ -276,5 +274,12 @@ "CJK Font": "CJK 글꼴", "Clear Search": "검색 지우기", "Header & Footer": "헤더 및 푸터", - "Apply also in Scrolled Mode": "스크롤 모드에서도 적용" + "Apply also in Scrolled Mode": "스크롤 모드에서도 적용", + "A new version of Readest is Available!": "Readest의 새 버전이 있습니다!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}}가 사용 가능 (설치된 버전 {{currentVersion}}).", + "Download and install now?": "지금 다운로드하고 설치하시겠습니까?", + "Downloading {{downloaded}} of {{contentLength}}": "다운로드 중 {{downloaded}} / {{contentLength}}", + "Download finished": "다운로드 완료", + "DOWNLOAD & INSTALL": "다운로드 및 설치", + "Changelog:": "변경 로그:" } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index 2769697c..65fb1858 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Zastosuj do wszystkich książek", "Apply to This Book": "Zastosuj do tej książki", "Unable to fetch the translation. Try again later.": "Nie udało się pobrać tłumaczenia. Spróbuj ponownie później.", - "Update Now!": "Zaktualizuj teraz!", - "Update": "Zaktualizuj", "Check Update": "Sprawdź aktualizację", "Already the latest version": "Już najnowsza wersja", "Book Details": "Szczegóły książki", @@ -276,5 +274,12 @@ "CJK Font": "Czcionka CJK", "Clear Search": "Wyczyść wyszukiwanie", "Header & Footer": "Nagłówek i stopka", - "Apply also in Scrolled Mode": "Zastosuj również w trybie przewijania" + "Apply also in Scrolled Mode": "Zastosuj również w trybie przewijania", + "A new version of Readest is Available!": "Nowa wersja Readest jest dostępna!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} jest dostępny (zainstalowana wersja {{currentVersion}}).", + "Download and install now?": "Pobierz i zainstaluj teraz?", + "Downloading {{downloaded}} of {{contentLength}}": "Pobieranie {{downloaded}} z {{contentLength}}", + "Download finished": "Pobieranie zakończone", + "DOWNLOAD & INSTALL": "POBIERZ I ZAINSTALUJ", + "Changelog:": "Dziennik zmian:" } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 491efac8..7100ec87 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Aplicar a todos os livros", "Apply to This Book": "Aplicar a este livro", "Unable to fetch the translation. Try again later.": "Não foi possível buscar a tradução. Tente novamente mais tarde.", - "Update Now!": "Atualizar Agora!", - "Update": "Atualizar", "Check Update": "Verificar atualização", "Already the latest version": "Já é a versão mais recente", "Book Details": "Detalhes do Livro", @@ -276,5 +274,12 @@ "CJK Font": "Fonte CJK", "Clear Search": "Limpar Pesquisa", "Header & Footer": "Cabeçalho e Rodapé", - "Apply also in Scrolled Mode": "Aplicar também no Modo Rolado" + "Apply also in Scrolled Mode": "Aplicar também no Modo Rolado", + "A new version of Readest is Available!": "Uma nova versão do Readest está disponível!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} está disponível (versão instalada {{currentVersion}}).", + "Download and install now?": "Baixar e instalar agora?", + "Downloading {{downloaded}} of {{contentLength}}": "Baixando {{downloaded}} de {{contentLength}}", + "Download finished": "Download concluído", + "DOWNLOAD & INSTALL": "BAIXAR E INSTALAR", + "Changelog:": "Notas de versão:" } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index a24409c0..851ae877 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Применить ко всем книгам", "Apply to This Book": "Применить к этой книге", "Unable to fetch the translation. Try again later.": "Не удалось получить перевод. Попробуйте позже.", - "Update Now!": "Обновить сейчас!", - "Update": "Обновить", "Check Update": "Проверить обновление", "Already the latest version": "Уже последняя версия", "Book Details": "Детали книги", @@ -276,5 +274,12 @@ "CJK Font": "CJK Шрифт", "Clear Search": "Очистить поиск", "Header & Footer": "Заголовок и нижний колонтитул", - "Apply also in Scrolled Mode": "Применить также в прокручиваемом режиме" + "Apply also in Scrolled Mode": "Применить также в прокручиваемом режиме", + "A new version of Readest is Available!": "Доступна новая версия Readest!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} доступен (установленная версия {{currentVersion}}).", + "Download and install now?": "Скачать и установить сейчас?", + "Downloading {{downloaded}} of {{contentLength}}": "Скачано {{downloaded}} из {{contentLength}}", + "Download finished": "Загрузка завершена", + "DOWNLOAD & INSTALL": "СКАЧАТЬ И УСТАНОВИТЬ", + "Changelog:": "Изменения:" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 9489b1c0..784eb0b0 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Tüm kitaplara uygula", "Apply to This Book": "Bu kitaba uygula", "Unable to fetch the translation. Try again later.": "Çeviri alınamıyor. Daha sonra tekrar deneyin.", - "Update Now!": "Şimdi Güncelle!", - "Update": "Güncelle", "Check Update": "Güncellemeyi kontrol et", "Already the latest version": "Zaten en son sürüm", "Book Details": "Kitap Detayları", @@ -276,5 +274,12 @@ "CJK Font": "CJK Yazı Tipi", "Clear Search": "Aramayı Temizle", "Header & Footer": "Başlık ve Altbilgi", - "Apply also in Scrolled Mode": "Kaydırılmış Modda da Uygula" + "Apply also in Scrolled Mode": "Kaydırılmış Modda da Uygula", + "A new version of Readest is Available!": "Yeni bir Readest sürümü mevcut!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} mevcut (yüklü sürüm {{currentVersion}}).", + "Download and install now?": "Şimdi indirip yükleyelim mi?", + "Downloading {{downloaded}} of {{contentLength}}": "İndiriliyor {{downloaded}}/{{contentLength}}", + "Download finished": "İndirme tamamlandı", + "DOWNLOAD & INSTALL": "İNDİR & YÜKLE", + "Changelog:": "Değişiklik Günlüğü:" } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index 9e4e9aa5..2e0d17b6 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Застосувати до всіх книг", "Apply to This Book": "Застосувати до цієї книги", "Unable to fetch the translation. Try again later.": "Не вдалося отримати переклад. Спробуйте пізніше.", - "Update Now!": "Оновити зараз!", - "Update": "Оновити", "Check Update": "Перевірити оновлення", "Already the latest version": "Вже остання версія", "Book Details": "Деталі книги", @@ -276,5 +274,12 @@ "CJK Font": "CJK шрифт", "Clear Search": "Очистити пошук", "Header & Footer": "Заголовок і нижній колонтитул", - "Apply also in Scrolled Mode": "Застосувати також у прокрученому режимі" + "Apply also in Scrolled Mode": "Застосувати також у прокрученому режимі", + "A new version of Readest is Available!": "Доступна нова версія Readest!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} доступна (встановлена версія {{currentVersion}}).", + "Download and install now?": "Завантажити та встановити зараз?", + "Downloading {{downloaded}} of {{contentLength}}": "Завантаження {{downloaded}} з {{contentLength}}", + "Download finished": "Завантаження завершено", + "DOWNLOAD & INSTALL": "ЗАВАНТАЖИТИ І ВСТАНОВИТИ", + "Changelog:": "Журнал змін:" } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index f390ddc6..c906485b 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "Áp dụng cho tất cả sách", "Apply to This Book": "Áp dụng cho sách này", "Unable to fetch the translation. Try again later.": "Không thể tải dịch vụ. Vui lòng thử lại sau.", - "Update Now!": "Cập nhật ngay!", - "Update": "Cập nhật", "Check Update": "Kiểm tra cập nhật", "Already the latest version": "Đã là phiên bản mới nhất", "Book Details": "Chi tiết sách", @@ -276,5 +274,12 @@ "CJK Font": "Phông chữ CJK", "Clear Search": "Xóa tìm kiếm", "Header & Footer": "Đầu trang & Chân trang", - "Apply also in Scrolled Mode": "Áp dụng cũng trong chế độ cuộn" + "Apply also in Scrolled Mode": "Áp dụng cũng trong chế độ cuộn", + "A new version of Readest is Available!": "Đã có phiên bản mới của Readest!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} đã có sẵn (phiên bản đã cài đặt {{currentVersion}}).", + "Download and install now?": "Tải xuống và cài đặt ngay bây giờ?", + "Downloading {{downloaded}} of {{contentLength}}": "Đang tải {{downloaded}} trong {{contentLength}}", + "Download finished": "Tải xuống hoàn tất", + "DOWNLOAD & INSTALL": "TẢI XUỐNG & CÀI ĐẶT", + "Changelog:": "Thay đổi:" } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index a10144f5..5c78d7a3 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "应用于所有书籍", "Apply to This Book": "应用于此书籍", "Unable to fetch the translation. Try again later.": "无法获取翻译,请稍后重试。", - "Update Now!": "立即更新!", - "Update": "更新", "Check Update": "检查更新", "Already the latest version": "已经是最新版本", "Book Details": "书籍详情", @@ -276,5 +274,12 @@ "CJK Font": "中文字体", "Clear Search": "清除搜索", "Header & Footer": "页眉页脚", - "Apply also in Scrolled Mode": "应用到滚动模式" + "Apply also in Scrolled Mode": "应用到滚动模式", + "A new version of Readest is Available!": "有新版本的 Readest 可更新!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} 可更新(已安装版本 {{currentVersion}})。", + "Download and install now?": "立即下载并安装?", + "Downloading {{downloaded}} of {{contentLength}}": "正在下载 {{downloaded}} / {{contentLength}}", + "Download finished": "下载完成", + "DOWNLOAD & INSTALL": "下载并安装", + "Changelog:": "更新日志:" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index 6ac61d2f..28ff7772 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -126,8 +126,6 @@ "Apply to All Books": "應用於所有書籍", "Apply to This Book": "應用於此書籍", "Unable to fetch the translation. Try again later.": "無法獲取翻譯,請稍後再試。", - "Update Now!": "立即更新!", - "Update": "更新", "Check Update": "檢查更新", "Already the latest version": "已經是最新版本", "Book Details": "書籍詳情", @@ -276,5 +274,12 @@ "CJK Font": "中文字體", "Clear Search": "清除搜索", "Header & Footer": "頁眉頁腳", - "Apply also in Scrolled Mode": "滾動模式同樣適用" + "Apply also in Scrolled Mode": "滾動模式同樣適用", + "A new version of Readest is Available!": "有新版本的 Readest 可更新!", + "Readest {{newVersion}} is available (installed version {{currentVersion}}).": "Readest {{newVersion}} 可更新(已安裝版本 {{currentVersion}})。", + "Download and install now?": "立即下載並安裝?", + "Downloading {{downloaded}} of {{contentLength}}": "正在下載 {{downloaded}} / {{contentLength}}", + "Download finished": "下載完成", + "DOWNLOAD & INSTALL": "下載並安裝", + "Changelog:": "更新日誌:" } diff --git a/apps/readest-app/src-tauri/capabilities/default.json b/apps/readest-app/src-tauri/capabilities/default.json index 0bc7d2f7..f47736f2 100644 --- a/apps/readest-app/src-tauri/capabilities/default.json +++ b/apps/readest-app/src-tauri/capabilities/default.json @@ -2,7 +2,7 @@ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "enables the default permissions", - "windows": ["main"], + "windows": ["main", "updater"], "permissions": [ "core:default", "fs:default", @@ -45,6 +45,9 @@ { "url": "https://*.deepl.com" }, + { + "url": "https://github.com/readest/*" + }, { "url": "https://*.cloudflarestorage.com" } @@ -65,6 +68,8 @@ "core:window:allow-toggle-maximize", "core:window:allow-set-fullscreen", "core:window:allow-set-always-on-top", + "core:webview:allow-create-webview-window", + "core:path:allow-resolve-directory", "log:default", "shell:default", "process:default", diff --git a/apps/readest-app/src-tauri/capabilities/desktop.json b/apps/readest-app/src-tauri/capabilities/desktop.json index c6851ffc..6e831916 100644 --- a/apps/readest-app/src-tauri/capabilities/desktop.json +++ b/apps/readest-app/src-tauri/capabilities/desktop.json @@ -1,10 +1,7 @@ { "$schema": "../gen/schemas/desktop-schema.json", "identifier": "desktop-capability", - "windows": ["main"], + "windows": ["main", "updater"], "platforms": ["linux", "macOS", "windows"], - "permissions": [ - "updater:default", - "cli:default" - ] + "permissions": ["updater:default", "cli:default"] } diff --git a/apps/readest-app/src-tauri/src/macos/traffic_light.rs b/apps/readest-app/src-tauri/src/macos/traffic_light.rs index d69f7fbf..5db6a64d 100644 --- a/apps/readest-app/src-tauri/src/macos/traffic_light.rs +++ b/apps/readest-app/src-tauri/src/macos/traffic_light.rs @@ -144,13 +144,14 @@ pub fn setup_traffic_light_positioner(window: Window) { .expect("NS window should exist on state to handle resize") as id; - #[cfg(target_os = "macos")] - position_traffic_lights( - UnsafeWindowHandle(id as *mut std::ffi::c_void), - TRAFFIC_LIGHTS_VISIBLE, - WINDOW_CONTROL_PAD_X, - WINDOW_CONTROL_PAD_Y, - ); + if state.window.label() == "main" { + position_traffic_lights( + UnsafeWindowHandle(id as *mut std::ffi::c_void), + TRAFFIC_LIGHTS_VISIBLE, + WINDOW_CONTROL_PAD_X, + WINDOW_CONTROL_PAD_Y, + ); + } }); let super_del: id = *this.get_ivar("super_delegate"); @@ -277,12 +278,14 @@ pub fn setup_traffic_light_positioner(window: Window) { .expect("Failed to emit event"); let id = state.window.ns_window().expect("Failed to emit event") as id; - position_traffic_lights( - UnsafeWindowHandle(id as *mut std::ffi::c_void), - TRAFFIC_LIGHTS_VISIBLE, - WINDOW_CONTROL_PAD_X, - WINDOW_CONTROL_PAD_Y, - ); + if state.window.label() == "main" { + position_traffic_lights( + UnsafeWindowHandle(id as *mut std::ffi::c_void), + TRAFFIC_LIGHTS_VISIBLE, + WINDOW_CONTROL_PAD_X, + WINDOW_CONTROL_PAD_Y, + ); + } }); let super_del: id = *this.get_ivar("super_delegate"); diff --git a/apps/readest-app/src/app/updater/page.tsx b/apps/readest-app/src/app/updater/page.tsx new file mode 100644 index 00000000..5a661ecd --- /dev/null +++ b/apps/readest-app/src/app/updater/page.tsx @@ -0,0 +1,251 @@ +'use client'; + +import clsx from 'clsx'; +import semver from 'semver'; +import Image from 'next/image'; +import { Suspense, useEffect, useState } from 'react'; +import { check, Update } from '@tauri-apps/plugin-updater'; +import { relaunch } from '@tauri-apps/plugin-process'; +import { fetch } from '@tauri-apps/plugin-http'; +import { useTranslation } from '@/hooks/useTranslation'; +import { useSearchParams } from 'next/navigation'; +import { useTheme } from '@/hooks/useTheme'; +import packageJson from '../../../package.json'; +import Spinner from '@/components/Spinner'; + +const CHANGELOG_URL = + 'https://github.com/readest/readest/releases/latest/download/release-notes.json'; + +interface ReleaseNotes { + releases: Record< + string, + { + date: string; + notes: string[]; + } + >; +} + +interface Changelog { + version: string; + date: string; + notes: string[]; +} + +const UpdaterDialog = () => { + const _ = useTranslation(); + const searchParams = useSearchParams(); + const currentVersion = packageJson.version; + const version = searchParams?.get('version') || ''; + const [update, setUpdate] = useState(null); + const [isMounted, setIsMounted] = useState(false); + const [newVersion, setNewVersion] = useState(version); + const [changelogs, setChangelogs] = useState([]); + const [progress, setProgress] = useState(null); + const [contentLength, setContentLength] = useState(null); + const [downloaded, setDownloaded] = useState(null); + + useEffect(() => { + const fetchChangelogs = async ( + fromVersion: string, + toVersion: string, + ): Promise => { + try { + const res = await fetch(CHANGELOG_URL); + const data: ReleaseNotes = await res.json(); + const releases = data.releases; + + const entries = Object.entries(releases) + .filter(([ver]) => semver.gt(ver, fromVersion) && semver.lte(ver, toVersion)) + .sort(([a], [b]) => semver.rcompare(a, b)) + .map(([version, info]) => ({ + version, + date: new Date(info.date).toDateString(), + notes: info.notes, + })); + + return entries; + } catch (error) { + console.error('Failed to fetch changelog:', error); + return []; + } + }; + const parseNumberedList = (input: string): string[] => { + return input + .split(/(?:^|\s)\d+\.\s/) + .map((item) => item.trim()) + .filter((item) => item.length > 0); + }; + const checkForUpdates = async () => { + const update = await check(); + setUpdate(update); + if (update) { + setNewVersion(update.version); + const changelogs = await fetchChangelogs(currentVersion, update.version); + if (changelogs.length > 0) { + setChangelogs(changelogs); + } else { + setChangelogs([ + { + version: update.version, + date: new Date(update.date!).toDateString(), + notes: parseNumberedList(update.body ?? ''), + }, + ]); + } + } + }; + checkForUpdates(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useTheme(); + + useEffect(() => { + setIsMounted(true); + }, []); + + const handleDownloadInstall = async () => { + if (!update) { + return; + } + console.log(`found update ${update.version} from ${update.date} with notes ${update.body}`); + let downloaded = 0; + let contentLength = 0; + let lastLogged = 0; + setProgress(0); + await update.downloadAndInstall((event) => { + switch (event.event) { + case 'Started': + contentLength = event.data.contentLength!; + setContentLength(contentLength); + console.log(`started downloading ${event.data.contentLength} bytes`); + break; + case 'Progress': + downloaded += event.data.chunkLength; + setDownloaded(downloaded); + const percent = Math.floor((downloaded / contentLength) * 100); + setProgress(percent); + if (downloaded - lastLogged >= 1 * 1024 * 1024) { + console.log(`downloaded ${downloaded} bytes from ${contentLength}`); + lastLogged = downloaded; + } + break; + case 'Finished': + console.log('download finished'); + setProgress(100); + break; + } + }); + console.log('update installed'); + await relaunch(); + }; + + if (!isMounted) { + return null; + } + + return ( +
+
+
+
+
+
+ Logo +
+
+ +
+

{_('A new version of Readest is Available!')}

+

+ {_('Readest {{newVersion}} is available (installed version {{currentVersion}}).', { + newVersion, + currentVersion, + })} +

+

{_('Download and install now?')}

+ +
+ {progress !== null && ( +
+ +

+ {progress < 100 + ? _('Downloading {{downloaded}} of {{contentLength}}', { + downloaded: downloaded + ? `${Math.floor(downloaded / 1024 / 1024)} MB` + : '0 MB', + contentLength: contentLength + ? `${Math.floor(contentLength / 1024 / 1024)} MB` + : '0 MB', + }) + : _('Download finished')} +

+
+ )} + +
+ +
+
+
+
+
+
+

{_('Changelog:')}

+
+ {changelogs.length > 0 ? ( + changelogs.map((entry: Changelog) => ( +
+

+ {entry.version} ({entry.date}) +

+
    + {entry.notes.map((note: string, i: number) => ( +
  • {note}
  • + ))} +
+
+ )) + ) : ( +
+
+
+
+
+ )} +
+
+
+
+ ); +}; + +const UpdaterPage = () => { + return ( + + + + } + > + + + ); +}; + +export default UpdaterPage; diff --git a/apps/readest-app/src/components/AboutWindow.tsx b/apps/readest-app/src/components/AboutWindow.tsx index d350712d..2e2927c3 100644 --- a/apps/readest-app/src/components/AboutWindow.tsx +++ b/apps/readest-app/src/components/AboutWindow.tsx @@ -55,14 +55,21 @@ export const AboutWindow = () => { {_('Version {{version}}', { version: packageJson.version })} {`(${browserInfo})`}

- {hasUpdater() && !isUpdated && ( - - {_('Check Update')} - - )} - {isUpdated && ( -

{_('Already the latest version')}

- )} +
+ {hasUpdater() && !isUpdated && ( + + {_('Check Update')} + + )} + {isUpdated && ( +

+ {_('Already the latest version')} +

+ )} +
diff --git a/apps/readest-app/src/helpers/updater.ts b/apps/readest-app/src/helpers/updater.ts index 4b51632b..69d751bd 100644 --- a/apps/readest-app/src/helpers/updater.ts +++ b/apps/readest-app/src/helpers/updater.ts @@ -1,6 +1,5 @@ import { check } from '@tauri-apps/plugin-updater'; -import { ask } from '@tauri-apps/plugin-dialog'; -import { relaunch } from '@tauri-apps/plugin-process'; +import { WebviewWindow } from '@tauri-apps/api/webviewWindow'; import { CHECK_UPDATE_INTERVAL_SEC } from '@/services/constants'; import { TranslationFunc } from '@/hooks/useTranslation'; @@ -17,45 +16,20 @@ export const checkForAppUpdates = async (_: TranslationFunc, autoCheck = true) = const update = await check(); console.log('Update found', update); if (update) { - const yes = await ask( - ` - Update to ${update.version} is available! - Release notes: ${update.body} - `, - { - title: _('Update Now!'), - kind: 'info', - okLabel: _('Update'), - cancelLabel: _('Cancel'), - }, - ); - - if (yes) { - console.log(`found update ${update.version} from ${update.date} with notes ${update.body}`); - let downloaded = 0; - let contentLength = 0; - let lastLogged = 0; - await update.downloadAndInstall((event) => { - switch (event.event) { - case 'Started': - contentLength = event.data.contentLength!; - console.log(`started downloading ${event.data.contentLength} bytes`); - break; - case 'Progress': - downloaded += event.data.chunkLength; - if (downloaded - lastLogged >= 1 * 1024 * 1024) { - console.log(`downloaded ${downloaded} bytes from ${contentLength}`); - lastLogged = downloaded; - } - break; - case 'Finished': - console.log('download finished'); - break; - } - }); - console.log('update installed'); - await relaunch(); - } + const win = new WebviewWindow('updater', { + url: `/updater?version=${update.version}`, + title: 'Software Update', + width: 626, + height: 406, + center: true, + resizable: true, + }); + win.once('tauri://created', () => { + console.log('new window created'); + }); + win.once('tauri://error', (e) => { + console.error('error creating window', e); + }); } return update; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 435d7960..008c15fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,6 +149,9 @@ importers: react-responsive: specifier: ^10.0.0 version: 10.0.0(react@19.0.0) + semver: + specifier: ^7.7.1 + version: 7.7.1 tinycolor2: specifier: ^1.6.0 version: 1.6.0 @@ -180,6 +183,9 @@ importers: '@types/react-dom': specifier: 18.3.1 version: 18.3.1 + '@types/semver': + specifier: ^7.7.0 + version: 7.7.0 '@types/tinycolor2': specifier: ^1.4.6 version: 1.4.6 @@ -2671,6 +2677,9 @@ packages: '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/semver@7.7.0': + resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} + '@types/tinycolor2@1.4.6': resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} @@ -5195,6 +5204,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + send@1.1.0: resolution: {integrity: sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==} engines: {node: '>= 18'} @@ -9427,6 +9441,8 @@ snapshots: '@types/resolve@1.20.2': {} + '@types/semver@7.7.0': {} + '@types/tinycolor2@1.4.6': {} '@types/trusted-types@2.0.7': {} @@ -9501,7 +9517,7 @@ snapshots: fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.3 + semver: 7.7.1 ts-api-utils: 1.4.3(typescript@5.7.2) optionalDependencies: typescript: 5.7.2 @@ -11148,7 +11164,7 @@ snapshots: is-bun-module@1.3.0: dependencies: - semver: 7.6.3 + semver: 7.7.1 is-callable@1.2.7: {} @@ -12157,6 +12173,8 @@ snapshots: semver@7.6.3: {} + semver@7.7.1: {} + send@1.1.0: dependencies: debug: 4.4.0 @@ -12217,7 +12235,7 @@ snapshots: dependencies: color: 4.2.3 detect-libc: 2.0.3 - semver: 7.6.3 + semver: 7.7.1 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.5 '@img/sharp-darwin-x64': 0.33.5