From b0cc0b6f1a461ff5082034b73875a0e0a3d4f2f8 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Tue, 27 May 2025 20:37:32 +0800 Subject: [PATCH] layout: better organized panels in settings dialog (#1246) --- .../public/locales/ar/translation.json | 7 +- .../public/locales/de/translation.json | 7 +- .../public/locales/el/translation.json | 7 +- .../public/locales/es/translation.json | 7 +- .../public/locales/fr/translation.json | 7 +- .../public/locales/hi/translation.json | 7 +- .../public/locales/id/translation.json | 7 +- .../public/locales/it/translation.json | 7 +- .../public/locales/ja/translation.json | 7 +- .../public/locales/ko/translation.json | 7 +- .../public/locales/nl/translation.json | 7 +- .../public/locales/pl/translation.json | 7 +- .../public/locales/pt/translation.json | 7 +- .../public/locales/ru/translation.json | 7 +- .../public/locales/tr/translation.json | 7 +- .../public/locales/uk/translation.json | 7 +- .../public/locales/vi/translation.json | 7 +- .../public/locales/zh-CN/translation.json | 7 +- .../public/locales/zh-TW/translation.json | 7 +- .../src/app/reader/components/HeaderBar.tsx | 2 +- .../reader/components/TranslationToggler.tsx | 10 +- .../components/settings/ControlPanel.tsx | 62 +++++-- .../reader/components/settings/DialogMenu.tsx | 6 +- .../reader/components/settings/FontPanel.tsx | 20 +-- .../reader/components/settings/LangPanel.tsx | 151 ++++++++++++++++ .../components/settings/LayoutPanel.tsx | 88 +++++---- .../reader/components/settings/MiscPanel.tsx | 157 ---------------- .../components/settings/SettingsDialog.tsx | 170 +++++++++--------- apps/readest-app/src/components/Button.tsx | 2 +- apps/readest-app/src/utils/lang.ts | 12 ++ 30 files changed, 447 insertions(+), 366 deletions(-) create mode 100644 apps/readest-app/src/app/reader/components/settings/LangPanel.tsx diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index 467e3224..a5317b65 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "مطابقة الكلمات الكاملة", "Maximum Number of Columns": "العدد الأقصى للأعمدة", "Minimum Font Size": "الحد الأدنى لحجم الخط", - "Misc": "أخرى", "Monospace Font": "خط أحادي المسافة (Monospace)", "More Info": "مزيد من المعلومات", "Nord": "نورد", @@ -305,7 +304,6 @@ "Details": "التفاصيل", "File Size:": "حجم الملف:", "Auto Detect": "الكشف التلقائي", - "Touch": "اللمس", "Next Section": "القسم التالي", "Previous Section": "القسم السابق", "Next Page": "الصفحة التالية", @@ -333,5 +331,8 @@ "Translation Service": "خدمة الترجمة", "Translate To": "ترجمة إلى", "Disable Translation": "تعطيل الترجمة", - "Overlap Margin": "هامش التداخل" + "Scroll": "تمرير", + "Overlap Pixels": "تداخل البكسلات", + "Click": "نقر", + "System Language": "لغة النظام" } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index dca5dbbf..1331376d 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Ganze Wörter", "Maximum Number of Columns": "Maximale Spaltenanzahl", "Minimum Font Size": "Minimale Schriftgröße", - "Misc": "Sonstiges", "Monospace Font": "Monospace-Schriftart", "More Info": "Weitere Informationen", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Details", "File Size:": "Dateigröße:", "Auto Detect": "Automatisch erkennen", - "Touch": "Berührung", "Next Section": "Nächster Abschnitt", "Previous Section": "Vorheriger Abschnitt", "Next Page": "Nächste Seite", @@ -329,5 +327,8 @@ "Translation Service": "Übersetzungsdienst", "Translate To": "Übersetzen nach", "Disable Translation": "Übersetzung deaktivieren", - "Overlap Margin": "Überlappungsrand" + "Scroll": "Scrollen", + "Overlap Pixels": "Überlappungspixel", + "Click": "Tippen", + "System Language": "Systemsprache" } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index 3c94576e..c514221a 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Ταίριασμα ολόκληρων λέξεων", "Maximum Number of Columns": "Μέγιστος αριθμός στηλών", "Minimum Font Size": "Ελάχιστο μέγεθος γραμματοσειράς", - "Misc": "Διάφορα", "Monospace Font": "Γραμματοσειρά σταθερού πλάτους", "More Info": "Περισσότερες πληροφορίες", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Πληρ.", "File Size:": "Μέγεθος αρχείου:", "Auto Detect": "Αυτόματη ανίχνευση", - "Touch": "Αφή", "Next Section": "Επόμενη ενότητα", "Previous Section": "Προηγούμενη ενότητα", "Next Page": "Επόμενη σελίδα", @@ -329,5 +327,8 @@ "Translation Service": "Υπηρεσία μετάφρασης", "Translate To": "Μετάφραση σε", "Disable Translation": "Απενεργοποίηση μετάφρασης", - "Overlap Margin": "Περιθώριο επικάλυψης" + "Scroll": "Κύλιση", + "Overlap Pixels": "Επικάλυψη εικονοστοιχείων", + "Click": "Κλικ", + "System Language": "Γλώσσα συστήματος" } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index e92e3894..3f539738 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Coincidir palabras completas", "Maximum Number of Columns": "Número máximo de columnas", "Minimum Font Size": "Tamaño de fuente mínimo", - "Misc": "Varios", "Monospace Font": "Fuente monoespaciada", "More Info": "Más información", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Detalles", "File Size:": "Peso del archivo:", "Auto Detect": "Detección automática", - "Touch": "Toque", "Next Section": "Siguiente sección", "Previous Section": "Sección anterior", "Next Page": "Página siguiente", @@ -330,5 +328,8 @@ "Translation Service": "Servicio de traducción", "Translate To": "Traducir a", "Disable Translation": "Deshabilitar traducción", - "Overlap Margin": "Margen de superposición" + "Scroll": "Desplazar", + "Overlap Pixels": "Superponer píxeles", + "Click": "Click", + "System Language": "Idioma del sistema" } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 0a81e7f4..fbe51045 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Mots entiers", "Maximum Number of Columns": "Nombre maximal de colonnes", "Minimum Font Size": "Taille minimale de police", - "Misc": "Divers", "Monospace Font": "Police monospace", "More Info": "Plus d'informations", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Détails", "File Size:": "Taille du fichier :", "Auto Detect": "Détection automatique", - "Touch": "Touch", "Next Section": "Section suivante", "Previous Section": "Section précédente", "Next Page": "Page suivante", @@ -330,5 +328,8 @@ "Translation Service": "Service de traduction", "Translate To": "Traduire vers", "Disable Translation": " désactiver la traduction", - "Overlap Margin": "Marges de chevauchement" + "Scroll": "Défilement", + "Overlap Pixels": "Pixels de chevauchement", + "Click": "Cliquer", + "System Language": "Langue du système" } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index 9244149f..8bca8da4 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "पूरे शब्द मैच करें", "Maximum Number of Columns": "कॉलम की अधिकतम संख्या", "Minimum Font Size": "न्यूनतम फ़ॉन्ट साइज़", - "Misc": "विविध", "Monospace Font": "मोनोस्पेस फ़ॉन्ट", "More Info": "अधिक जानकारी", "Nord": "नॉर्ड", @@ -305,7 +304,6 @@ "Details": "विवरण", "File Size:": "फ़ाइल आकार:", "Auto Detect": "स्वचालित पहचान", - "Touch": "स्पर्श", "Next Section": "अगला अनुभाग", "Previous Section": "पिछला अनुभाग", "Next Page": "अगला पृष्ठ", @@ -329,5 +327,8 @@ "Translation Service": "अनुवाद सेवा", "Translate To": "अनुवाद करें", "Disable Translation": "अनुवाद अक्षम करें", - "Overlap Margin": "ओवरलैप मार्जिन" + "Scroll": "स्क्रॉल", + "Overlap Pixels": "ओवरलैप पिक्सेल", + "Click": "क्लिक करें", + "System Language": "सिस्टम भाषा" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index 10305e49..81e01c80 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Cocokkan Kata Utuh", "Maximum Number of Columns": "Jumlah Kolom Maksimum", "Minimum Font Size": "Ukuran Font Minimum", - "Misc": "Lain-lain", "Monospace Font": "Font Monospace", "More Info": "Info Lebih Lanjut", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Detail", "File Size:": "Ukuran File:", "Auto Detect": "Deteksi Otomatis", - "Touch": "Sentuh", "Next Section": "Bagian Selanjutnya", "Previous Section": "Bagian Sebelumnya", "Next Page": "Halaman Berikutnya", @@ -328,5 +326,8 @@ "Translation Service": "Layanan Terjemahan", "Translate To": "Terjemahkan Ke", "Disable Translation": "Nonaktifkan Terjemahan", - "Overlap Margin": "Margin Tumpang Tindih" + "Scroll": "Scroll", + "Overlap Pixels": "Overlap Piksel", + "Click": "Klik", + "System Language": "Bahasa Sistem" } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index 17337076..a203446e 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Parole intere", "Maximum Number of Columns": "Numero massimo di colonne", "Minimum Font Size": "Dimensione minima font", - "Misc": "Varie", "Monospace Font": "Font monospazio", "More Info": "Maggiori informazioni", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Dettagli", "File Size:": "Dimensione file:", "Auto Detect": "Rilevamento automatico", - "Touch": "Touch", "Next Section": "Sezione successiva", "Previous Section": "Sezione precedente", "Next Page": "Pagina successiva", @@ -330,5 +328,8 @@ "Translation Service": "Servizio di traduzione", "Translate To": "Traduci in", "Disable Translation": "Disabilita traduzione", - "Overlap Margin": "Margine di sovrapposizione" + "Scroll": "Scorri", + "Overlap Pixels": "Pixel di sovrapposizione", + "Click": "Fai clic", + "System Language": "Lingua di sistema" } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index eb5ed833..0bffeb8f 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "単語全体を一致", "Maximum Number of Columns": "最大列数", "Minimum Font Size": "最小フォントサイズ", - "Misc": "その他", "Monospace Font": "等幅フォント", "More Info": "詳細情報", "Nord": "ノルド", @@ -305,7 +304,6 @@ "Details": "詳細", "File Size:": "ファイルサイズ:", "Auto Detect": "自動検出", - "Touch": "タッチ", "Next Section": "次のセクション", "Previous Section": "前のセクション", "Next Page": "次のページ", @@ -328,5 +326,8 @@ "Translation Service": "翻訳サービス", "Translate To": "翻訳先", "Disable Translation": "翻訳を無効にする", - "Overlap Margin": "オーバーラップマージン" + "Scroll": "スクロール", + "Overlap Pixels": "重なりピクセル", + "Click": "クリック", + "System Language": "システム言語" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index a11fc836..79608d5b 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "전체 단어 일치", "Maximum Number of Columns": "최대 열 수", "Minimum Font Size": "최소 글꼴 크기", - "Misc": "기타", "Monospace Font": "고정폭 글꼴", "More Info": "추가 정보", "Nord": "노드", @@ -305,7 +304,6 @@ "Details": "세부정보", "File Size:": "파일 크기:", "Auto Detect": "자동 감지", - "Touch": "터치", "Next Section": "다음 섹션", "Previous Section": "이전 섹션", "Next Page": "다음 페이지", @@ -328,5 +326,8 @@ "Translation Service": "번역 서비스", "Translate To": "번역 대상 언어", "Disable Translation": "번역 비활성화", - "Overlap Margin": "겹침 여백" + "Scroll": "스크롤", + "Overlap Pixels": "겹치는 픽셀", + "Click": "클릭", + "System Language": "시스템 언어" } diff --git a/apps/readest-app/public/locales/nl/translation.json b/apps/readest-app/public/locales/nl/translation.json index e435ea77..843ea8d5 100644 --- a/apps/readest-app/public/locales/nl/translation.json +++ b/apps/readest-app/public/locales/nl/translation.json @@ -197,7 +197,6 @@ "Font": "Lettertype", "Layout": "Opmaak", "Color": "Kleur", - "Misc": "Overig", "(from 'As You Like It', Act II)": "(uit 'As You Like It', Akte II)", "Custom Theme": "Aangepast thema", "Theme Name": "Themanaam", @@ -305,7 +304,6 @@ "Reveal in Folder": "Tonen in map", "Don’t have an account? Sign up": "Nog geen account? Registreer u", "All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "De hele wereld is een toneel,\nEn alle mannen en vrouwen slechts spelers;\nZij hebben hun uitgangen en hun entrees,\nEn één man speelt in zijn tijd vele rollen,\nZijn daden zijnde zeven leeftijden.\n\n— William Shakespeare", - "Touch": "Raak", "Next Section": "Volgende sectie", "Previous Section": "Vorige sectie", "Next Page": "Volgende pagina", @@ -329,5 +327,8 @@ "Translation Service": "Vertaalservice", "Translate To": "Vertalen naar", "Disable Translation": "Vertaling uitschakelen", - "Overlap Margin": "Overlap marge" + "Scroll": "Scrollen", + "Overlap Pixels": "Overlap pixels", + "Click": "Klik", + "System Language": "Systemtaal" } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index f6a389bc..44b17824 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Uwzględnij całe słowa", "Maximum Number of Columns": "Maksymalna liczba kolumn", "Minimum Font Size": "Minimalny rozmiar czcionki", - "Misc": "Różne", "Monospace Font": "Czcionka o stałej szerokości", "More Info": "Więcej informacji", "Nord": "Północny", @@ -305,7 +304,6 @@ "Details": "Szczegóły", "File Size:": "Rozmiar pliku:", "Auto Detect": "Automatyczne wykrywanie", - "Touch": "Dotyk", "Next Section": "Następna sekcja", "Previous Section": "Poprzednia sekcja", "Next Page": "Następna strona", @@ -331,5 +329,8 @@ "Translation Service": "Usługa tłumaczenia", "Translate To": "Przetłumacz na", "Disable Translation": "Wyłącz tłumaczenie", - "Overlap Margin": "Margines nakładania" + "Scroll": "Przewijaj", + "Overlap Pixels": "Przesunięcie pikseli", + "Click": "Kliknij", + "System Language": "Język systemu" } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 29ea6531..dc4ea729 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Corresponder Palavras Inteiras", "Maximum Number of Columns": "Número Máximo de Colunas", "Minimum Font Size": "Tamanho Mínimo da Fonte", - "Misc": "Diversos", "Monospace Font": "Fonte Monoespaçada", "More Info": "Mais Informações", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Detalhes", "File Size:": "Tamanho do arquivo:", "Auto Detect": "Detectar Automaticamente", - "Touch": "Toque", "Next Section": "Próxima seção", "Previous Section": "Seção anterior", "Next Page": "Próxima página", @@ -330,5 +328,8 @@ "Translation Service": "Serviço de tradução", "Translate To": "Traduzir para", "Disable Translation": "Desativar tradução", - "Overlap Margin": "Margem de Sobreposição" + "Scroll": "Rolar", + "Overlap Pixels": "Sobreposição de Pixels", + "Click": "Clique", + "System Language": "Idioma do Sistema" } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 7a678289..eed9137c 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Только целые слова", "Maximum Number of Columns": "Максимальное количество колонок", "Minimum Font Size": "Минимальный размер шрифта", - "Misc": "Разное", "Monospace Font": "Моноширинный шрифт", "More Info": "Подробнее", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Инфо", "File Size:": "Размер файла:", "Auto Detect": "Автоопределение", - "Touch": "Сенсорный экран", "Next Section": "Следующий раздел", "Previous Section": "Предыдущий раздел", "Next Page": "Следующая страница", @@ -331,5 +329,8 @@ "Translation Service": "Сервис перевода", "Translate To": "Перевести на", "Disable Translation": "Отключить перевод", - "Overlap Margin": "Поле перекрытия" + "Scroll": "Прокрутка", + "Overlap Pixels": "Перекрывающиеся пиксели", + "Click": "Клик", + "System Language": "Системный язык" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 1ecf3f80..4af22a73 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Tam Kelimeleri Eşleştir", "Maximum Number of Columns": "Maksimum Sütun Sayısı", "Minimum Font Size": "Minimum Yazı Boyutu", - "Misc": "Diğer", "Monospace Font": "Eş Aralıklı Yazı Tipi", "More Info": "Daha Fazla Bilgi", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Detaylar", "File Size:": "Dosya Boyutu:", "Auto Detect": "Algıla", - "Touch": "Dokunmatik", "Next Section": "Sonraki Bölüm", "Previous Section": "Önceki Bölüm", "Next Page": "Sonraki Sayfa", @@ -329,5 +327,8 @@ "Translation Service": "Çeviri Hizmeti", "Translate To": "Şuna Çevir", "Disable Translation": "Çeviriyi Devre Dışı Bırak", - "Overlap Margin": "Çakışma Kenar Boşluğu" + "Scroll": "Kaydır", + "Overlap Pixels": "Örtüşen Pikseller", + "Click": "Klik", + "System Language": "System Dili" } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index be6c83b2..6227ec5e 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Шукати цілі слова", "Maximum Number of Columns": "Максимальна кількість колонок", "Minimum Font Size": "Мінімальний розмір шрифту", - "Misc": "Різне", "Monospace Font": "Моноширинний шрифт", "More Info": "Більше інформації", "Nord": "Північний", @@ -305,7 +304,6 @@ "Details": "Деталі", "File Size:": "Розмір файлу:", "Auto Detect": "Авто виявлення", - "Touch": "Дотик", "Next Section": "Наступний розділ", "Previous Section": "Попередній розділ", "Next Page": "Наступна сторінка", @@ -331,5 +329,8 @@ "Translation Service": "Служба перекладу", "Translate To": "Перекласти на", "Disable Translation": "Вимкнути переклад", - "Overlap Margin": "Відступ перекриття" + "Scroll": "Прокрутка", + "Overlap Pixels": "Пікселі перекриття", + "Click": "Клацнути", + "System Language": "Системна мова" } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index b848638d..554f7b31 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "Khớp toàn bộ từ", "Maximum Number of Columns": "Số cột tối đa", "Minimum Font Size": "Cỡ chữ tối thiểu", - "Misc": "Khác", "Monospace Font": "Phông chữ đơn cách", "More Info": "Thông tin thêm", "Nord": "Nord", @@ -305,7 +304,6 @@ "Details": "Chi tiết", "File Size:": "Kích thước tệp:", "Auto Detect": "Phát hiện tự động", - "Touch": "Chạm", "Next Section": "Phần tiếp theo", "Previous Section": "Phần trước", "Next Page": "Trang tiếp theo", @@ -328,5 +326,8 @@ "Translation Service": "Dịch vụ dịch thuật", "Translate To": "Dịch sang", "Disable Translation": "Tắt dịch", - "Overlap Margin": "Độ chồng lề" + "Scroll": "Cuộn", + "Overlap Pixels": "Chồng lấn pixel", + "Click": "Nhấp", + "System Language": "Ngôn ngữ hệ thống" } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index 5c119fda..70e0fdcb 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "匹配整个单词", "Maximum Number of Columns": "分栏数", "Minimum Font Size": "最小字号", - "Misc": "杂项", "Monospace Font": "等宽字体", "More Info": "更多信息", "Nord": "极光", @@ -305,7 +304,6 @@ "Details": "详情", "File Size:": "文件大小", "Auto Detect": "自动检测", - "Touch": "触控", "Next Section": "下一章", "Previous Section": "上一章", "Next Page": "下一页", @@ -328,5 +326,8 @@ "Translation Service": "翻译服务", "Translate To": "翻译到", "Disable Translation": "禁用翻译", - "Overlap Margin": "重叠边距" + "Scroll": "滚动", + "Overlap Pixels": "重叠像素", + "Click": "点击", + "System Language": "系统语言" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index ac47ddd3..743105df 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -59,7 +59,6 @@ "Match Whole Words": "匹配整個單詞", "Maximum Number of Columns": "分欄數", "Minimum Font Size": "最小字號", - "Misc": "雜項", "Monospace Font": "等寬字體", "More Info": "更多信息", "Nord": "極光", @@ -305,7 +304,6 @@ "Details": "詳情", "File Size:": "檔案大小", "Auto Detect": "自動檢測", - "Touch": "觸控", "Next Section": "下一章", "Previous Section": "上一章", "Next Page": "下一頁", @@ -328,5 +326,8 @@ "Translation Service": "翻譯服務", "Translate To": "翻譯至", "Disable Translation": "停用翻譯", - "Overlap Margin": "重疊邊距" + "Scroll": "滾動", + "Overlap Pixels": "重疊像素", + "Click": "點擊", + "System Language": "系統語言" } diff --git a/apps/readest-app/src/app/reader/components/HeaderBar.tsx b/apps/readest-app/src/app/reader/components/HeaderBar.tsx index beb506fd..f63ff98f 100644 --- a/apps/readest-app/src/app/reader/components/HeaderBar.tsx +++ b/apps/readest-app/src/app/reader/components/HeaderBar.tsx @@ -129,8 +129,8 @@ const HeaderBar: React.FC = ({
- + { const _ = useTranslation(); const { envConfig } = useEnv(); + const { getBookData } = useBookDataStore(); const { getViewSettings, setViewSettings, setHoveredBookKey } = useReaderStore(); + + const bookData = getBookData(bookKey); const viewSettings = getViewSettings(bookKey)!; const [translationEnabled, setTranslationEnabled] = useState(viewSettings.translationEnabled!); @@ -28,6 +33,9 @@ const TranslationToggler = ({ bookKey }: { bookKey: string }) => { icon={ } + disabled={ + !bookData || isSameLang(bookData.book?.primaryLanguage, viewSettings.translateTargetLang!) + } onClick={() => setTranslationEnabled(!translationEnabled)} tooltip={translationEnabled ? _('Disable Translation') : _('Enable Translation')} tooltipDirection='bottom' diff --git a/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx b/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx index b78e6652..c5f0bc62 100644 --- a/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx +++ b/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx @@ -21,6 +21,7 @@ const ControlPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { const [volumeKeysToFlip, setVolumeKeysToFlip] = useState(viewSettings.volumeKeysToFlip!); const [isDisableClick, setIsDisableClick] = useState(viewSettings.disableClick!); const [swapClickArea, setSwapClickArea] = useState(viewSettings.swapClickArea!); + const [animated, setAnimated] = useState(viewSettings.animated!); useEffect(() => { if (isScrolledMode === viewSettings.scrolled) return; @@ -67,10 +68,20 @@ const ControlPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [swapClickArea]); + useEffect(() => { + saveViewSettings(envConfig, bookKey, 'animated', animated, false, false); + if (animated) { + getView(bookKey)?.renderer.setAttribute('animated', ''); + } else { + getView(bookKey)?.renderer.removeAttribute('animated'); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [animated]); + return (
-

{_('Touch')}

+

{_('Scroll')}

@@ -92,7 +103,7 @@ const ControlPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { />
= ({ bookKey }) => { max={200} step={10} /> - {appService?.isMobileApp && ( -
- {_('Volume Keys for Page Flip')} - setVolumeKeysToFlip(!volumeKeysToFlip)} - /> -
- )} +
+
+
+ +
+

{_('Click')}

+
+
{_('Clicks for Page Flip')} = ({ bookKey }) => { onChange={() => setSwapClickArea(!swapClickArea)} />
+ {appService?.isMobileApp && ( +
+ {_('Volume Keys for Page Flip')} + setVolumeKeysToFlip(!volumeKeysToFlip)} + /> +
+ )} +
+
+
+ +
+

{_('Animation')}

+
+
+
+ {_('Paging Animation')} + setAnimated(!animated)} + /> +
diff --git a/apps/readest-app/src/app/reader/components/settings/DialogMenu.tsx b/apps/readest-app/src/app/reader/components/settings/DialogMenu.tsx index e1d837b0..55c67aad 100644 --- a/apps/readest-app/src/app/reader/components/settings/DialogMenu.tsx +++ b/apps/readest-app/src/app/reader/components/settings/DialogMenu.tsx @@ -1,3 +1,4 @@ +import clsx from 'clsx'; import React from 'react'; import { MdCheck } from 'react-icons/md'; import { useSettingsStore } from '@/store/settingsStore'; @@ -21,7 +22,10 @@ const DialogMenu: React.FC = ({ toggleDropdown }) => { return (
-
+
+

{_('Writing Mode')}

+
+
+ +
-
- -
+
+ +
-
- -
+
+ +
-
- -
+
+
@@ -390,15 +397,6 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { onChange={() => setHyphenation(!hyphenation)} />
-
- {_('Override Book Layout')} - setOverrideLayout(!overrideLayout)} - /> -
diff --git a/apps/readest-app/src/app/reader/components/settings/MiscPanel.tsx b/apps/readest-app/src/app/reader/components/settings/MiscPanel.tsx index 4971f192..f0f654a0 100644 --- a/apps/readest-app/src/app/reader/components/settings/MiscPanel.tsx +++ b/apps/readest-app/src/app/reader/components/settings/MiscPanel.tsx @@ -1,6 +1,5 @@ import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; -import i18n from 'i18next'; import { IoPhoneLandscapeOutline, IoPhonePortraitOutline } from 'react-icons/io5'; import { MdOutlineScreenRotation } from 'react-icons/md'; import { useEnv } from '@/context/EnvContext'; @@ -10,11 +9,8 @@ import { useTranslation } from '@/hooks/useTranslation'; import { getStyles } from '@/utils/style'; import { lockScreenOrientation } from '@/utils/bridge'; import { saveViewSettings } from '../../utils/viewSettingsHelper'; -import { getTranslators } from '@/services/translators'; -import { TRANSLATED_LANGS } from '@/services/constants'; import cssbeautify from 'cssbeautify'; import cssValidate from '@/utils/css'; -import DropDown from './DropDown'; const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { const _ = useTranslation(); @@ -23,13 +19,9 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { const { getView, getViewSettings, setViewSettings } = useReaderStore(); const viewSettings = getViewSettings(bookKey)!; - const [animated, setAnimated] = useState(viewSettings.animated!); const [draftStylesheet, setDraftStylesheet] = useState(viewSettings.userStylesheet!); const [draftStylesheetSaved, setDraftStylesheetSaved] = useState(true); const [screenOrientation, setScreenOrientation] = useState(viewSettings.screenOrientation!); - const [translationEnabled, setTranslationEnabled] = useState(viewSettings.translationEnabled!); - const [translationProvider, setTranslationProvider] = useState(viewSettings.translationProvider!); - const [translateTargetLang, setTranslateTargetLang] = useState(viewSettings.translateTargetLang!); const [error, setError] = useState(null); const [inputFocusInAndroid, setInputFocusInAndroid] = useState(false); @@ -101,74 +93,6 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { } }; - const getCurrentUILangOption = () => { - const uiLanguage = viewSettings.uiLanguage; - return { - option: uiLanguage, - label: - uiLanguage === '' - ? _('Auto') - : TRANSLATED_LANGS[uiLanguage as keyof typeof TRANSLATED_LANGS], - }; - }; - - const getLangOptions = () => { - const langs = TRANSLATED_LANGS as Record; - const options = Object.entries(langs).map(([option, label]) => ({ option, label })); - options.sort((a, b) => a.label.localeCompare(b.label)); - options.unshift({ option: '', label: _('Auto') }); - return options; - }; - - const handleSelectUILang = (option: string) => { - saveViewSettings(envConfig, bookKey, 'uiLanguage', option, false, false); - i18n.changeLanguage(option ? option : navigator.language); - }; - - const getTranslationProviderOptions = () => { - const translators = getTranslators(); - const availableProviders = translators.map((t) => { - return { option: t.name, label: t.label }; - }); - return availableProviders; - }; - - const getCurrentTranslationProviderOption = () => { - const option = translationProvider; - const availableProviders = getTranslationProviderOptions(); - return availableProviders.find((p) => p.option === option) || availableProviders[0]!; - }; - - const handleSelectTranslationProvider = (option: string) => { - setTranslationProvider(option); - saveViewSettings(envConfig, bookKey, 'translationProvider', option, false, false); - viewSettings.translationProvider = option; - setViewSettings(bookKey, { ...viewSettings }); - }; - - const getCurrentTargetLangOption = () => { - const option = translateTargetLang; - const availableOptions = getLangOptions(); - return availableOptions.find((o) => o.option === option) || availableOptions[0]!; - }; - - const handleSelectTargetLang = (option: string) => { - setTranslateTargetLang(option); - saveViewSettings(envConfig, bookKey, 'translateTargetLang', option, false, false); - viewSettings.translateTargetLang = option; - setViewSettings(bookKey, { ...viewSettings }); - }; - - useEffect(() => { - saveViewSettings(envConfig, bookKey, 'animated', animated, false, false); - if (animated) { - getView(bookKey)?.renderer.setAttribute('animated', ''); - } else { - getView(bookKey)?.renderer.removeAttribute('animated'); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [animated]); - useEffect(() => { saveViewSettings(envConfig, bookKey, 'screenOrientation', screenOrientation, false, false); if (appService?.isMobileApp) { @@ -177,14 +101,6 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [screenOrientation]); - useEffect(() => { - if (translationEnabled === viewSettings.translationEnabled) return; - saveViewSettings(envConfig, bookKey, 'translationEnabled', translationEnabled, true, false); - viewSettings.translationEnabled = translationEnabled; - setViewSettings(bookKey, { ...viewSettings }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [translationEnabled]); - return (
= ({ bookKey }) => { inputFocusInAndroid && 'h-[50%] overflow-y-auto pb-[200px]', )} > -
-

{_('Language')}

-
-
-
- {_('Interface Language')} - -
-
-
-
- -
-

{_('Translation')}

-
-
-
- {_('Enable Translation')} - setTranslationEnabled(!translationEnabled)} - /> -
- -
- {_('Translation Service')} - -
- -
- {_('Translate To')} - -
-
-
-
- -
-

{_('Animation')}

-
-
-
- {_('Paging Animation')} - setAnimated(!animated)} - /> -
-
-
-
- {appService?.isMobileApp && (

{_('Screen')}

diff --git a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx index 71d85d94..aac2f61a 100644 --- a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx +++ b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx @@ -5,7 +5,7 @@ import { useEnv } from '@/context/EnvContext'; import { useSettingsStore } from '@/store/settingsStore'; import { useTranslation } from '@/hooks/useTranslation'; import { RiFontSize } from 'react-icons/ri'; -import { RiDashboardLine } from 'react-icons/ri'; +import { RiDashboardLine, RiTranslate } from 'react-icons/ri'; import { VscSymbolColor } from 'react-icons/vsc'; import { PiDotsThreeVerticalBold } from 'react-icons/pi'; import { LiaHandPointerSolid } from 'react-icons/lia'; @@ -19,9 +19,10 @@ import Dropdown from '@/components/Dropdown'; import Dialog from '@/components/Dialog'; import DialogMenu from './DialogMenu'; import ControlPanel from './ControlPanel'; +import LangPanel from './LangPanel'; import MiscPanel from './MiscPanel'; -type SettingsPanelType = 'Font' | 'Layout' | 'Color' | 'Control' | 'Misc'; +type SettingsPanelType = 'Font' | 'Layout' | 'Color' | 'Control' | 'Language' | 'Custom'; type TabConfig = { tab: SettingsPanelType; @@ -34,10 +35,7 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo const { appService } = useEnv(); const [isRtl] = useState(() => getDirFromUILanguage() === 'rtl'); const tabsRef = useRef(null); - const [showTabLabels, setShowTabLabels] = useState(false); - const [activePanel, setActivePanel] = useState( - (localStorage.getItem('lastConfigPanel') || 'Font') as SettingsPanelType, - ); + const [showAllTabLabels, setShowAllTabLabels] = useState(false); const { setFontLayoutSettingsDialogOpen } = useSettingsStore(); const tabConfig = [ @@ -62,12 +60,25 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo label: _('Behavior'), }, { - tab: 'Misc', + tab: 'Language', + icon: RiTranslate, + label: _('Language'), + }, + { + tab: 'Custom', icon: IoAccessibilityOutline, - label: _('Misc'), + label: _('Custom'), }, ] as TabConfig[]; + const [activePanel, setActivePanel] = useState(() => { + const lastPanel = localStorage.getItem('lastConfigPanel'); + if (lastPanel && tabConfig.some((tab) => tab.tab === lastPanel)) { + return lastPanel as SettingsPanelType; + } + return 'Font' as SettingsPanelType; + }); + const handleSetActivePanel = (tab: SettingsPanelType) => { setActivePanel(tab); localStorage.setItem('lastConfigPanel', tab); @@ -82,7 +93,7 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo if (!container) return; const checkButtonWidths = () => { - const threshold = (container.clientWidth - 64) * 0.25; + const threshold = (container.clientWidth - 64) * 0.22; const hideLabel = Array.from(container.querySelectorAll('button')).some((button) => { const labelSpan = button.querySelector('span'); const labelText = labelSpan?.textContent || ''; @@ -100,7 +111,7 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo document.body.removeChild(clone); return fullWidth > threshold; }); - setShowTabLabels(!hideLabel); + setShowAllTabLabels(!hideLabel); }; checkButtonWidths(); @@ -120,83 +131,82 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo }, []); return ( - <> - + + +
+ {tabConfig.map(({ tab, icon: Icon, label }) => ( + + ))} +
+
+ } + > + + -
- {tabConfig.map(({ tab, icon: Icon, label }) => ( - - ))} -
-
- } - > - - - -
- } - > - {activePanel === 'Font' && } - {activePanel === 'Layout' && } - {activePanel === 'Color' && } - {activePanel === 'Control' && } - {activePanel === 'Misc' && } -
- +
+ } + > + {activePanel === 'Font' && } + {activePanel === 'Layout' && } + {activePanel === 'Color' && } + {activePanel === 'Control' && } + {activePanel === 'Language' && } + {activePanel === 'Custom' && } + ); }; diff --git a/apps/readest-app/src/components/Button.tsx b/apps/readest-app/src/components/Button.tsx index 853bb538..f586b338 100644 --- a/apps/readest-app/src/components/Button.tsx +++ b/apps/readest-app/src/components/Button.tsx @@ -35,7 +35,7 @@ const Button: React.FC = ({ className={clsx( 'btn btn-ghost h-8 min-h-8 w-8 p-0', appService?.isMobileApp && 'hover:bg-transparent', - disabled && 'btn-disabled !bg-transparent', + disabled && 'btn-disabled !bg-transparent opacity-50', className, )} onClick={disabled ? undefined : onClick} diff --git a/apps/readest-app/src/utils/lang.ts b/apps/readest-app/src/utils/lang.ts index 42a892ff..64794305 100644 --- a/apps/readest-app/src/utils/lang.ts +++ b/apps/readest-app/src/utils/lang.ts @@ -39,3 +39,15 @@ export const localeToLang = (locale: string): string => { } return mapping[locale] || locale.split('-')[0]!.toLowerCase(); }; + +export const normalizedLangCode = (lang: string | null | undefined): string => { + if (!lang) return ''; + return lang.split('-')[0]!.toLowerCase(); +}; + +export const isSameLang = (lang1?: string | null, lang2?: string | null): boolean => { + if (!lang1 || !lang2) return false; + const normalizedLang1 = normalizedLangCode(lang1); + const normalizedLang2 = normalizedLangCode(lang2); + return normalizedLang1 === normalizedLang2; +};