fix(a11y): updating progress info when navigating with screen readers (#3182)

Also add some missing button labels for screen readers
This commit is contained in:
Huang Xin
2026-02-06 15:43:03 +08:00
committed by GitHub
parent 681e065ac4
commit fe9603ffb8
42 changed files with 568 additions and 129 deletions
@@ -1023,7 +1023,6 @@
"{{count}} book(s) synced_other": "تمت مزامنة {{count}} كتاب",
"Unable to start RSVP": "تعذر بدء RSVP",
"RSVP not supported for PDF": "RSVP غير مدعوم لملفات PDF",
"Close RSVP": "إغلاق RSVP",
"Select Chapter": "اختر الفصل",
"{{number}} WPM": "{{number}} كلمة في الدقيقة",
"Context": "السياق",
@@ -1059,10 +1058,25 @@
"Scroll right": "تمرير لليمين",
"Library Sync Progress": "تقدم تزامن المكتبة",
"Back to library": "العودة إلى المكتبة",
"Manual": "يدوي",
"Group by...": "تجميع حسب...",
"Export as Plain Text": "تصدير كنص بسيط",
"Export as Markdown": "تصدير بصيغة Markdown",
"Show Page Navigation Buttons": "أزرار التنقل",
"Page {{number}}": "صفحة {{number}}"
"Page {{number}}": "صفحة {{number}}",
"highlight": "تمييز",
"underline": "تسطير",
"squiggly": "متعرج",
"red": "أحمر",
"violet": "بنفسجي",
"blue": "أزرق",
"green": "أخضر",
"yellow": "أصفر",
"Select {{style}} style": "اختر نمط {{style}}",
"Select {{color}} color": "اختر لون {{color}}",
"Close Book": "إغلاق الكتاب",
"Speed Reading": "القراءة السريعة",
"Close Speed Reading": "إغلاق القراءة السريعة",
"Authors": "المؤلفون",
"Books": "الكتب",
"Groups": "المجموعات"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}}টি বই সিঙ্ক করা হয়েছে",
"Unable to start RSVP": "RSVP शुरू করতে অসমর্থ",
"RSVP not supported for PDF": "PDF-এর জন্য RSVP সমর্থিত নয়",
"Close RSVP": "RSVP বন্ধ করুন",
"Select Chapter": "অধ্যায় নির্বাচন করুন",
"{{number}} WPM": "{{number}} WPM",
"Context": "প্রসঙ্গ",
@@ -1011,10 +1010,25 @@
"Scroll right": "ডানে স্ক্রোল করুন",
"Library Sync Progress": "লাইব্রেরি সিঙ্ক অগ্রগতি",
"Back to library": "লাইব্রেরিতে ফিরে যান",
"Manual": "ম্যানুয়াল",
"Group by...": "গ্রুপ অনুযায়ী...",
"Export as Plain Text": "সাধারণ টেক্সট হিসেবে এক্সপোর্ট করুন",
"Export as Markdown": "Markdown হিসেবে এক্সপোর্ট করুন",
"Show Page Navigation Buttons": "নেভিগেশন বোতাম",
"Page {{number}}": "পৃষ্ঠা {{number}}"
"Page {{number}}": "পৃষ্ঠা {{number}}",
"highlight": "হাইলাইট",
"underline": "আন্ডারলাইন",
"squiggly": "এঁকেবেঁকে চলা",
"red": "লাল",
"violet": "বেগুনী",
"blue": "নীল",
"green": "সবুজ",
"yellow": "হলুদ",
"Select {{style}} style": "{{style}} স্টাইল নির্বাচন করুন",
"Select {{color}} color": "{{color}} রঙ নির্বাচন করুন",
"Close Book": "বই বন্ধ করুন",
"Speed Reading": "দ্রুত পঠন",
"Close Speed Reading": "দ্রুত পঠন বন্ধ করুন",
"Authors": "লেখকগণ",
"Books": "বই",
"Groups": "দল"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "དེབ་ {{count}} མཉམ་འགྲིག་བྱས་ཟིན།",
"Unable to start RSVP": "RSVP འགོ་འཛུགས་མ་ཐུབ།",
"RSVP not supported for PDF": "PDF ལ་ RSVP རྒྱབ་སྐྱོར་མེད།",
"Close RSVP": "RSVP ཁ་རྒྱག་པ།",
"Select Chapter": "ལེའུ་འདེམས་པ།",
"{{number}} WPM": "{{number}} WPM",
"Context": "བརྗོད་དོན།",
@@ -999,10 +998,25 @@
"Scroll right": "གཡས་ལ་བཤུད་དགོས།",
"Library Sync Progress": "དཔེ་མཛོད་མཉམ་འབྱུང་གི་རིམ་པ།",
"Back to library": "དཔེ་མཛོད་ལ་ལོག་པ།",
"Manual": "ལག་བཟོས།",
"Group by...": "དབྱེ་བ་འབྱེད་སྟངས།...",
"Export as Plain Text": "ཡིག་རྐྱང་དཀྱུས་མར་ཕྱིར་འདྲེན།",
"Export as Markdown": "Markdown དུ་ཕྱིར་འདྲེན།",
"Show Page Navigation Buttons": "ཤོག་ངོས་མཐེབ་གནོན།",
"Page {{number}}": "ཤོག་ལྷེ། {{number}}"
"Page {{number}}": "ཤོག་ལྷེ། {{number}}",
"highlight": "འོད་རྟགས།",
"underline": "ཞབས་ཐིག",
"squiggly": "ཀྱག་ཀྱག་ཐིག",
"red": "དམར་པོ།",
"violet": "སྨུག་པོ།",
"blue": "སྔོན་པོ།",
"green": "ལྗང་ཁུ།",
"yellow": "སེར་པོ།",
"Select {{style}} style": "{{style}} བཟོ་ལྟ་བདམ་པ།",
"Select {{color}} color": "{{color}} ཚོན་མདོག་བདམ་པ།",
"Close Book": "དེབ་ཁ་རྒྱག་པ།",
"Speed Reading": "མགྱོགས་ཀློག",
"Close Speed Reading": "མགྱོགས་ཀློག་ཁ་རྒྱག་པ།",
"Authors": "རྩོམ་པ་པོ།",
"Books": "དཔེ་ཆ།",
"Groups": "ཚོགས་པ།"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} Bücher synchronisiert",
"Unable to start RSVP": "RSVP kann nicht gestartet werden",
"RSVP not supported for PDF": "RSVP wird für PDF nicht unterstützt",
"Close RSVP": "RSVP schließen",
"Select Chapter": "Kapitel auswählen",
"{{number}} WPM": "{{number}} WPM",
"Context": "Kontext",
@@ -1011,10 +1010,25 @@
"Scroll right": "Nach rechts scrollen",
"Library Sync Progress": "Bibliotheks-Synchronisierungsfortschritt",
"Back to library": "Zurück zur Bibliothek",
"Manual": "Manuell",
"Group by...": "Gruppieren nach...",
"Export as Plain Text": "Als reinen Text exportieren",
"Export as Markdown": "Als Markdown exportieren",
"Show Page Navigation Buttons": "Navigationsschaltflächen",
"Page {{number}}": "Seite {{number}}"
"Page {{number}}": "Seite {{number}}",
"highlight": "Hervorhebung",
"underline": "Unterstreichung",
"squiggly": "geschlängelt",
"red": "rot",
"violet": "violett",
"blue": "blau",
"green": "grün",
"yellow": "gelb",
"Select {{style}} style": "Stil {{style}} auswählen",
"Select {{color}} color": "Farbe {{color}} auswählen",
"Close Book": "Buch schließen",
"Speed Reading": "Schnelllesen",
"Close Speed Reading": "Schnelllesen schließen",
"Authors": "Autoren",
"Books": "Bücher",
"Groups": "Gruppen"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} βιβλία συγχρονίστηκαν",
"Unable to start RSVP": "Αδυναμία έναρξης RSVP",
"RSVP not supported for PDF": "Το RSVP δεν υποστηρίζεται για PDF",
"Close RSVP": "Κλείσιμο RSVP",
"Select Chapter": "Επιλογή Κεφαλαίου",
"{{number}} WPM": "{{number}} WPM",
"Context": "Πλαίσιο",
@@ -1011,10 +1010,25 @@
"Scroll right": "Κύλιση δεξιά",
"Library Sync Progress": "Πρόοδος συγχρονισμού βιβλιοθήκης",
"Back to library": "Επιστροφή στη βιβλιοθήκη",
"Manual": "Χειροκίνητα",
"Group by...": "Ομαδοποίηση κατά...",
"Export as Plain Text": "Αποστολή ως απλό κείμενο",
"Export as Markdown": "Αποστολή ως Markdown",
"Show Page Navigation Buttons": "Κουμπιά πλοήγησης",
"Page {{number}}": "Σελίδα {{number}}"
"Page {{number}}": "Σελίδα {{number}}",
"highlight": "επισήμανση",
"underline": "υπογράμμιση",
"squiggly": "κυματιστή γραμμή",
"red": "κόκκινο",
"violet": "βιολετί",
"blue": "μπλε",
"green": "πράσινο",
"yellow": "κίτρινο",
"Select {{style}} style": "Επιλέξτε στυλ {{style}}",
"Select {{color}} color": "Επιλέξτε χρώμα {{color}}",
"Close Book": "Κλείσιμο βιβλίου",
"Speed Reading": "Γρήγορη Ανάγνωση",
"Close Speed Reading": "Κλείσιμο Γρήγορης Ανάγνωσης",
"Authors": "Συγγραφείς",
"Books": "Βιβλία",
"Groups": "Ομάδες"
}
@@ -987,7 +987,6 @@
"{{count}} book(s) synced_other": "{{count}} libros sincronizados",
"Unable to start RSVP": "No se puede iniciar RSVP",
"RSVP not supported for PDF": "RSVP no es compatible con PDF",
"Close RSVP": "Cerrar RSVP",
"Select Chapter": "Seleccionar capítulo",
"{{number}} WPM": "{{number}} PPM",
"Context": "Contexto",
@@ -1023,10 +1022,25 @@
"Scroll right": "Desplazar a la derecha",
"Library Sync Progress": "Progreso de sincronización de la biblioteca",
"Back to library": "Volver a la biblioteca",
"Manual": "Manual",
"Group by...": "Agrupar por...",
"Export as Plain Text": "Exportar como texto sin formato",
"Export as Markdown": "Exportar como Markdown",
"Show Page Navigation Buttons": "Botones de navegación",
"Page {{number}}": "Página {{number}}"
"Page {{number}}": "Página {{number}}",
"highlight": "resaltado",
"underline": "subrayado",
"squiggly": "ondulado",
"red": "rojo",
"violet": "violeta",
"blue": "azul",
"green": "verde",
"yellow": "amarillo",
"Select {{style}} style": "Seleccionar estilo {{style}}",
"Select {{color}} color": "Seleccionar color {{color}}",
"Close Book": "Cerrar libro",
"Speed Reading": "Lectura rápida",
"Close Speed Reading": "Cerrar lectura rápida",
"Authors": "Autores",
"Books": "Libros",
"Groups": "Grupos"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} کتاب همگام شدند",
"Unable to start RSVP": "قادر به شروع RSVP نیست",
"RSVP not supported for PDF": "RSVP برای PDF پشتیبانی نمی‌شود",
"Close RSVP": "بستن RSVP",
"Select Chapter": "انتخاب فصل",
"{{number}} WPM": "{{number}} کلمه در دقیقه",
"Context": "زمینه",
@@ -1011,10 +1010,25 @@
"Scroll right": "اسکرول به راست",
"Library Sync Progress": "پیشرفت همگام‌سازی کتابخانه",
"Back to library": "بازگشت به کتابخانه",
"Manual": "دستی",
"Group by...": "گروه‌بندی بر اساس...",
"Export as Plain Text": "خروجی به صورت متن ساده",
"Export as Markdown": "خروجی به صورت Markdown",
"Show Page Navigation Buttons": "دکمه‌های ناوبری",
"Page {{number}}": "صفحه {{number}}"
"Page {{number}}": "صفحه {{number}}",
"highlight": "هایلایت",
"underline": "زیرخط",
"squiggly": "موج‌دار",
"red": "قرمز",
"violet": "بنفش",
"blue": "آبی",
"green": "سبز",
"yellow": "زرد",
"Select {{style}} style": "انتخاب سبک {{style}}",
"Select {{color}} color": "انتخاب رنگ {{color}}",
"Close Book": "بستن کتاب",
"Speed Reading": "تندخوانی",
"Close Speed Reading": "بستن تندخوانی",
"Authors": "نویسندگان",
"Books": "کتاب‌ها",
"Groups": "گروه‌ها"
}
@@ -987,7 +987,6 @@
"{{count}} book(s) synced_other": "{{count}} livres synchronisés",
"Unable to start RSVP": "Impossible de démarrer RSVP",
"RSVP not supported for PDF": "RSVP non pris en charge pour PDF",
"Close RSVP": "Fermer RSVP",
"Select Chapter": "Sélectionner le chapitre",
"{{number}} WPM": "{{number}} MPM",
"Context": "Contexte",
@@ -1023,10 +1022,25 @@
"Scroll right": "Défiler vers la droite",
"Library Sync Progress": "Progression de la synchronisation de la bibliothèque",
"Back to library": "Retour à la bibliothèque",
"Manual": "Manuel",
"Group by...": "Grouper par...",
"Export as Plain Text": "Exporter en texte brut",
"Export as Markdown": "Exporter en Markdown",
"Show Page Navigation Buttons": "Boutons de navigation",
"Page {{number}}": "Page {{number}}"
"Page {{number}}": "Page {{number}}",
"highlight": "surlignage",
"underline": "soulignage",
"squiggly": "ondulé",
"red": "rouge",
"violet": "violet",
"blue": "bleu",
"green": "vert",
"yellow": "jaune",
"Select {{style}} style": "Sélectionner le style {{style}}",
"Select {{color}} color": "Sélectionner la couleur {{color}}",
"Close Book": "Fermer le livre",
"Speed Reading": "Lecture rapide",
"Close Speed Reading": "Fermer la lecture rapide",
"Authors": "Auteurs",
"Books": "Livres",
"Groups": "Groupes"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} पुस्तकें सिंक की गईं",
"Unable to start RSVP": "RSVP शुरू करने में असमर्थ",
"RSVP not supported for PDF": "PDF के लिए RSVP समर्थित नहीं है",
"Close RSVP": "RSVP बंद करें",
"Select Chapter": "अध्याय चुनें",
"{{number}} WPM": "{{number}} WPM",
"Context": "संदर्भ",
@@ -1011,10 +1010,25 @@
"Scroll right": "दाएं स्क्रॉल करें",
"Library Sync Progress": "पुस्तकालय सिंक प्रगति",
"Back to library": "लाइब्रेरी पर वापस जाएं",
"Manual": "मैनुअल",
"Group by...": "इसके द्वारा समूहबद्ध करें...",
"Export as Plain Text": "प्लेन टेक्स्ट के रूप में एक्सपोर्ट करें",
"Export as Markdown": "Markdown के रूप में एक्सपोर्ट करें",
"Show Page Navigation Buttons": "नेविगेशन बटन",
"Page {{number}}": "पृष्ठ {{number}}"
"Page {{number}}": "पृष्ठ {{number}}",
"highlight": "हाइलाइट",
"underline": "अंडरलाइन",
"squiggly": "टेढ़ी-मेढ़ी रेखा",
"red": "लाल",
"violet": "बैंगनी",
"blue": "नीला",
"green": "हरा",
"yellow": "पीला",
"Select {{style}} style": "{{style}} शैली चुनें",
"Select {{color}} color": "{{color}} रंग चुनें",
"Close Book": "किताब बंद करें",
"Speed Reading": "तीव्र पठन",
"Close Speed Reading": "तीव्र पठन बंद करें",
"Authors": "लेखक",
"Books": "पुस्तकें",
"Groups": "समूह"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "{{count}} buku telah disinkronkan",
"Unable to start RSVP": "Tidak dapat memulai RSVP",
"RSVP not supported for PDF": "RSVP tidak didukung untuk PDF",
"Close RSVP": "Tutup RSVP",
"Select Chapter": "Pilih Bab",
"{{number}} WPM": "{{number}} WPM",
"Context": "Konteks",
@@ -999,10 +998,25 @@
"Scroll right": "Gulir ke kanan",
"Library Sync Progress": "Kemajuan Sinkronisasi Pustaka",
"Back to library": "Kembali ke perpustakaan",
"Manual": "Manual",
"Group by...": "Kelompokkan menurut...",
"Export as Plain Text": "Ekspor sebagai Teks Biasa",
"Export as Markdown": "Ekspor sebagai Markdown",
"Show Page Navigation Buttons": "Tombol navigasi",
"Page {{number}}": "Halaman {{number}}"
"Page {{number}}": "Halaman {{number}}",
"highlight": "sorotan",
"underline": "garis bawah",
"squiggly": "bergelombang",
"red": "merah",
"violet": "ungu",
"blue": "biru",
"green": "hijau",
"yellow": "kuning",
"Select {{style}} style": "Pilih gaya {{style}}",
"Select {{color}} color": "Pilih warna {{color}}",
"Close Book": "Tutup Buku",
"Speed Reading": "Membaca Cepat",
"Close Speed Reading": "Tutup Membaca Cepat",
"Authors": "Penulis",
"Books": "Buku",
"Groups": "Grup"
}
@@ -987,7 +987,6 @@
"{{count}} book(s) synced_other": "{{count}} libri sincronizzati",
"Unable to start RSVP": "Impossibile avviare RSVP",
"RSVP not supported for PDF": "RSVP non supportato per PDF",
"Close RSVP": "Chiudi RSVP",
"Select Chapter": "Seleziona capitolo",
"{{number}} WPM": "{{number}} PPM",
"Context": "Contesto",
@@ -1023,10 +1022,25 @@
"Scroll right": "Scorri a destra",
"Library Sync Progress": "Avanzamento sincronizzazione libreria",
"Back to library": "Torna alla libreria",
"Manual": "Manuale",
"Group by...": "Raggruppa per...",
"Export as Plain Text": "Esporta come testo normale",
"Export as Markdown": "Esporta come Markdown",
"Show Page Navigation Buttons": "Tasti navigazione",
"Page {{number}}": "Pagina {{number}}"
"Page {{number}}": "Pagina {{number}}",
"highlight": "evidenziazione",
"underline": "sottolineatura",
"squiggly": "ondulato",
"red": "rosso",
"violet": "viola",
"blue": "blu",
"green": "verde",
"yellow": "giallo",
"Select {{style}} style": "Seleziona lo stile {{style}}",
"Select {{color}} color": "Seleziona il colore {{color}}",
"Close Book": "Chiudi libro",
"Speed Reading": "Lettura veloce",
"Close Speed Reading": "Chiudi lettura veloce",
"Authors": "Autori",
"Books": "Libri",
"Groups": "Gruppi"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "{{count}} 冊の本が同期されました",
"Unable to start RSVP": "RSVPを起動できません",
"RSVP not supported for PDF": "PDFはRSVPに対応していません",
"Close RSVP": "RSVPを閉じる",
"Select Chapter": "章を選択",
"{{number}} WPM": "{{number}} WPM",
"Context": "コンテキスト",
@@ -999,10 +998,25 @@
"Scroll right": "右にスクロール",
"Library Sync Progress": "ライブラリ同期の進捗",
"Back to library": "ライブラリに戻る",
"Manual": "手動",
"Group by...": "グループ化...",
"Export as Plain Text": "プレーンテキストとして書き出し",
"Export as Markdown": "Markdownとして書き出し",
"Show Page Navigation Buttons": "ナビゲーションボタンを表示",
"Page {{number}}": "{{number}} ページ"
"Page {{number}}": "{{number}} ページ",
"highlight": "ハイライト",
"underline": "下線",
"squiggly": "波線",
"red": "赤",
"violet": "すみれ色",
"blue": "青",
"green": "緑",
"yellow": "黄色",
"Select {{style}} style": "スタイル {{style}} を選択",
"Select {{color}} color": "色 {{color}} を選択",
"Close Book": "本を閉じる",
"Speed Reading": "速読",
"Close Speed Reading": "速読を閉じる",
"Authors": "著者",
"Books": "書籍",
"Groups": "グループ"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "{{count}}권의 책이 동기화되었습니다",
"Unable to start RSVP": "RSVP를 시작할 수 없습니다",
"RSVP not supported for PDF": "PDF는 RSVP를 지원하지 않습니다",
"Close RSVP": "RSVP 닫기",
"Select Chapter": "챕터 선택",
"{{number}} WPM": "{{number}} WPM",
"Context": "문맥",
@@ -999,10 +998,25 @@
"Scroll right": "오른쪽으로 스크롤",
"Library Sync Progress": "라이브러리 동기화 진행 상황",
"Back to library": "라이브러리로 돌아가기",
"Manual": "수동",
"Group by...": "그룹화 기준...",
"Export as Plain Text": "일반 텍스트로 내보내기",
"Export as Markdown": "Markdown으로 내보내기",
"Show Page Navigation Buttons": "탐색 버튼 표시",
"Page {{number}}": "{{number}} 페이지"
"Page {{number}}": "{{number}} 페이지",
"highlight": "하이라이트",
"underline": "밑줄",
"squiggly": "구불구불한 선",
"red": "빨간색",
"violet": "보라색",
"blue": "파란색",
"green": "초록색",
"yellow": "노란색",
"Select {{style}} style": "{{style}} 스타일 선택",
"Select {{color}} color": "{{color}} 색상 선택",
"Close Book": "책 닫기",
"Speed Reading": "속독",
"Close Speed Reading": "속독 닫기",
"Authors": "저자",
"Books": "도서",
"Groups": "그룹"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "{{count}} buku telah disegerakkan",
"Unable to start RSVP": "Tidak dapat memulakan RSVP",
"RSVP not supported for PDF": "RSVP tidak disokong untuk PDF",
"Close RSVP": "Tutup RSVP",
"Select Chapter": "Pilih Bab",
"{{number}} WPM": "{{number}} WPM",
"Context": "Konteks",
@@ -999,10 +998,25 @@
"Scroll right": "Tatal ke kanan",
"Library Sync Progress": "Kemajuan Segerak Perpustakaan",
"Back to library": "Kembali ke perpustakaan",
"Manual": "Manual",
"Group by...": "Kumpulan mengikut...",
"Export as Plain Text": "Eksport sebagai Teks Biasa",
"Export as Markdown": "Eksport sebagai Markdown",
"Show Page Navigation Buttons": "Butang navigasi",
"Page {{number}}": "Halaman {{number}}"
"Page {{number}}": "Halaman {{number}}",
"highlight": "serlah",
"underline": "garis bawah",
"squiggly": "berombak",
"red": "merah",
"violet": "ungu",
"blue": "biru",
"green": "hijau",
"yellow": "kuning",
"Select {{style}} style": "Pilih gaya {{style}}",
"Select {{color}} color": "Pilih warna {{color}}",
"Close Book": "Tutup Buku",
"Speed Reading": "Bacaan Pantas",
"Close Speed Reading": "Tutup Bacaan Pantas",
"Authors": "Penulis",
"Books": "Buku",
"Groups": "Kumpulan"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} boeken gesynchroniseerd",
"Unable to start RSVP": "Kan RSVP niet starten",
"RSVP not supported for PDF": "RSVP niet ondersteund voor PDF",
"Close RSVP": "RSVP sluiten",
"Select Chapter": "Hoofdstuk selecteren",
"{{number}} WPM": "{{number}} WPM",
"Context": "Context",
@@ -1011,10 +1010,25 @@
"Scroll right": "Naar rechts scrollen",
"Library Sync Progress": "Voortgang bibliotheeksynchronisatie",
"Back to library": "Terug naar bibliotheek",
"Manual": "Handmatig",
"Group by...": "Groeperen op...",
"Export as Plain Text": "Exporteren als platte tekst",
"Export as Markdown": "Exporteren als Markdown",
"Show Page Navigation Buttons": "Navigatieknoppen",
"Page {{number}}": "Pagina {{number}}"
"Page {{number}}": "Pagina {{number}}",
"highlight": "markering",
"underline": "onderstreping",
"squiggly": "gegolfd",
"red": "rood",
"violet": "paars",
"blue": "blauw",
"green": "groen",
"yellow": "geel",
"Select {{style}} style": "Selecteer {{style}} stijl",
"Select {{color}} color": "Selecteer {{color}} kleur",
"Close Book": "Boek sluiten",
"Speed Reading": "Snel lezen",
"Close Speed Reading": "Snel lezen sluiten",
"Authors": "Auteurs",
"Books": "Boeken",
"Groups": "Groepen"
}
@@ -999,7 +999,6 @@
"{{count}} book(s) synced_other": "{{count}} książek zsynchronizowanych",
"Unable to start RSVP": "Nie można uruchomić RSVP",
"RSVP not supported for PDF": "RSVP nie jest obsługiwane dla PDF",
"Close RSVP": "Zamknij RSVP",
"Select Chapter": "Wybierz rozdział",
"{{number}} WPM": "{{number}} WPM",
"Context": "Kontekst",
@@ -1035,10 +1034,25 @@
"Scroll right": "Przewiń w prawo",
"Library Sync Progress": "Postęp synchronizacji biblioteki",
"Back to library": "Powrót do biblioteki",
"Manual": "Ręcznie",
"Group by...": "Grupuj według...",
"Export as Plain Text": "Eksportuj jako zwykły tekst",
"Export as Markdown": "Eksportuj jako Markdown",
"Show Page Navigation Buttons": "Przyciski nawigacji",
"Page {{number}}": "Strona {{number}}"
"Page {{number}}": "Strona {{number}}",
"highlight": "wyróżnienie",
"underline": "podkreślenie",
"squiggly": "wężyk",
"red": "czerwony",
"violet": "fioletowy",
"blue": "niebieski",
"green": "zielony",
"yellow": "żółty",
"Select {{style}} style": "Wybierz styl {{style}}",
"Select {{color}} color": "Wybierz kolor {{color}}",
"Close Book": "Zamknij książkę",
"Speed Reading": "Szybkie czytanie",
"Close Speed Reading": "Zamknij szybkie czytanie",
"Authors": "Autorzy",
"Books": "Książki",
"Groups": "Grupy"
}
@@ -987,7 +987,6 @@
"{{count}} book(s) synced_other": "{{count}} livros sincronizados",
"Unable to start RSVP": "Não foi possível iniciar o RSVP",
"RSVP not supported for PDF": "RSVP não suportado para PDF",
"Close RSVP": "Fechar RSVP",
"Select Chapter": "Selecionar capítulo",
"{{number}} WPM": "{{number}} PPM",
"Context": "Contexto",
@@ -1023,10 +1022,25 @@
"Scroll right": "Rolar para a direita",
"Library Sync Progress": "Progresso de sincronização da biblioteca",
"Back to library": "Voltar à biblioteca",
"Manual": "Manual",
"Group by...": "Agrupar por...",
"Export as Plain Text": "Exportar como texto simples",
"Export as Markdown": "Exportar como Markdown",
"Show Page Navigation Buttons": "Botões de navegação",
"Page {{number}}": "Página {{number}}"
"Page {{number}}": "Página {{number}}",
"highlight": "destaque",
"underline": "sublinhado",
"squiggly": "ondulado",
"red": "vermelho",
"violet": "violeta",
"blue": "azul",
"green": "verde",
"yellow": "amarelo",
"Select {{style}} style": "Selecionar estilo {{style}}",
"Select {{color}} color": "Selecionar cor {{color}}",
"Close Book": "Fechar livro",
"Speed Reading": "Leitura rápida",
"Close Speed Reading": "Fechar leitura rápida",
"Authors": "Autores",
"Books": "Livros",
"Groups": "Grupos"
}
@@ -999,7 +999,6 @@
"{{count}} book(s) synced_other": "{{count}} книг синхронизировано",
"Unable to start RSVP": "Не удалось запустить RSVP",
"RSVP not supported for PDF": "RSVP не поддерживается для PDF",
"Close RSVP": "Закрыть RSVP",
"Select Chapter": "Выбрать главу",
"{{number}} WPM": "{{number}} WPM",
"Context": "Контекст",
@@ -1035,10 +1034,25 @@
"Scroll right": "Прокрутить вправо",
"Library Sync Progress": "Прогресс синхронизации библиотеки",
"Back to library": "Назад в библиотеку",
"Manual": "Вручную",
"Group by...": "Группировать по...",
"Export as Plain Text": "Экспортировать как обычный текст",
"Export as Markdown": "Экспортировать как Markdown",
"Show Page Navigation Buttons": "Кнопки навигации",
"Page {{number}}": "Страница {{number}}"
"Page {{number}}": "Страница {{number}}",
"highlight": "выделение",
"underline": "подчеркивание",
"squiggly": "волнистая линия",
"red": "красный",
"violet": "фиолетовый",
"blue": "синий",
"green": "зеленый",
"yellow": "желтый",
"Select {{style}} style": "Выбрать стиль {{style}}",
"Select {{color}} color": "Выбрать цвет {{color}}",
"Close Book": "Закрыть книгу",
"Speed Reading": "Скорочтение",
"Close Speed Reading": "Закрыть скорочтение",
"Authors": "Авторы",
"Books": "Книги",
"Groups": "Группы"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} පොත් සමමුහුර්ත කරන ලදී",
"Unable to start RSVP": "RSVP ආරම්භ කිරීමට නොහැක",
"RSVP not supported for PDF": "PDF සඳහා RSVP සහාය නොදක්වයි",
"Close RSVP": "RSVP වසන්න",
"Select Chapter": "පරිච්ඡේදය තෝරන්න",
"{{number}} WPM": "{{number}} WPM",
"Context": "සන්දර්භය",
@@ -1011,10 +1010,25 @@
"Scroll right": "දකුණට අනුචලනය කරන්න",
"Library Sync Progress": "පුස්තකාල සමමුහුර්ත කිරීමේ ප්‍රගතිය",
"Back to library": "පුස්තකාලයට ආපසු",
"Manual": "අත්පොත",
"Group by...": "මගින් සමූහනය කරන්න...",
"Export as Plain Text": "සාමාන්‍ය පෙළ ලෙස අපනයනය කරන්න",
"Export as Markdown": "Markdown ලෙස අපනයනය කරන්න",
"Show Page Navigation Buttons": "සංචාලන බොත්තම්",
"Page {{number}}": "පිටුව {{number}}"
"Page {{number}}": "පිටුව {{number}}",
"highlight": "මතුකර පෙන්වීම",
"underline": "යටින් ඉරි ඇඳීම",
"squiggly": "zigzag",
"red": "රතු",
"violet": "දම්",
"blue": "නිල්",
"green": "කොළ",
"yellow": "කහ",
"Select {{style}} style": "{{style}} විලාසය තෝරන්න",
"Select {{color}} color": "{{color}} වර්ණය තෝරන්න",
"Close Book": "පොත වසා දමන්න",
"Speed Reading": "වේග කියවීම",
"Close Speed Reading": "වේග කියවීම වසන්න",
"Authors": "කතුවරුන්",
"Books": "පොත්",
"Groups": "කණ්ඩායම්"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} böcker synkroniserade",
"Unable to start RSVP": "Kunde inte starta RSVP",
"RSVP not supported for PDF": "RSVP stöds inte för PDF",
"Close RSVP": "Stäng RSVP",
"Select Chapter": "Välj kapitel",
"{{number}} WPM": "{{number}} ord/min",
"Context": "Sammanhang",
@@ -1011,10 +1010,25 @@
"Scroll right": "Scrolla åt höger",
"Library Sync Progress": "Synkroniseringsframsteg för bibliotek",
"Back to library": "Tillbaka till biblioteket",
"Manual": "Manuellt",
"Group by...": "Gruppera efter...",
"Export as Plain Text": "Exportera som vanlig text",
"Export as Markdown": "Exportera som Markdown",
"Show Page Navigation Buttons": "Navigeringsknappar",
"Page {{number}}": "Sida {{number}}"
"Page {{number}}": "Sida {{number}}",
"highlight": "markering",
"underline": "understrykning",
"squiggly": "vågig linje",
"red": "röd",
"violet": "lila",
"blue": "blå",
"green": "grön",
"yellow": "gul",
"Select {{style}} style": "Välj stil {{style}}",
"Select {{color}} color": "Välj färg {{color}}",
"Close Book": "Stäng bok",
"Speed Reading": "Snabbläsning",
"Close Speed Reading": "Stäng snabbläsning",
"Authors": "Författare",
"Books": "Böcker",
"Groups": "Grupper"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} புத்தகங்கள் ஒத்திசைக்கப்பட்டன",
"Unable to start RSVP": "RSVP-ஐத் தொடங்க முடியவில்லை",
"RSVP not supported for PDF": "PDF-க்கு RSVP ஆதரவு இல்லை",
"Close RSVP": "RSVP-ஐ மூடு",
"Select Chapter": "அத்தியாயத்தைத் தேர்ந்தெடு",
"{{number}} WPM": "{{number}} WPM",
"Context": "சூழல்",
@@ -1011,10 +1010,25 @@
"Scroll right": "வலதுபுறம் உருட்டவும்",
"Library Sync Progress": "நூலக ஒத்திசைவு நிலை",
"Back to library": "நூலகத்திற்குத் திரும்பு",
"Manual": "கையேடு",
"Group by...": "இதன் படி குழுவாக்கு...",
"Export as Plain Text": "எளிய உரையாக ஏற்றுமதி செய்",
"Export as Markdown": "Markdown ஆக ஏற்றுமதி செய்",
"Show Page Navigation Buttons": "வழிசெலுத்தல் பொத்தான்கள்",
"Page {{number}}": "பக்கம் {{number}}"
"Page {{number}}": "பக்கம் {{number}}",
"highlight": "சிறப்பித்துக் காட்டு",
"underline": "அடிக்கோடு",
"squiggly": "வளைந்த கோடு",
"red": "சிவப்பு",
"violet": "ஊதா",
"blue": "நீலம்",
"green": "பச்சை",
"yellow": "மஞ்சள்",
"Select {{style}} style": "{{style}} பாணியைத் தேர்ந்தெடுக்கவும்",
"Select {{color}} color": "{{color}} நிறத்தைத் தேர்ந்தெடுக்கவும்",
"Close Book": "புத்தகத்தை மூடு",
"Speed Reading": "வேக வாசிப்பு",
"Close Speed Reading": "வேக வாசிப்பை மூடு",
"Authors": "ஆசிரியர்கள்",
"Books": "புத்தகங்கள்",
"Groups": "குழுக்கள்"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "ซิงค์หนังสือ {{count}} เล่มแล้ว",
"Unable to start RSVP": "ไม่สามารถเริ่ม RSVP ได้",
"RSVP not supported for PDF": "ไม่รองรับ RSVP สำหรับ PDF",
"Close RSVP": "ปิด RSVP",
"Select Chapter": "เลือกบท",
"{{number}} WPM": "{{number}} WPM",
"Context": "บริบท",
@@ -999,10 +998,25 @@
"Scroll right": "เลื่อนไปทางขวา",
"Library Sync Progress": "ความคืบหน้าการซิงค์ห้องสมุด",
"Back to library": "กลับไปที่ห้องสมุด",
"Manual": "ทำเอง",
"Group by...": "จัดกลุ่มตาม...",
"Export as Plain Text": "ส่งออกเป็นข้อความธรรมดา",
"Export as Markdown": "ส่งออกเป็น Markdown",
"Show Page Navigation Buttons": "ปุ่มนำทาง",
"Page {{number}}": "หน้า {{number}}"
"Page {{number}}": "หน้า {{number}}",
"highlight": "ไฮไลต์",
"underline": "ขีดเส้นใต้",
"squiggly": "เส้นหยัก",
"red": "สีแดง",
"violet": "สีม่วง",
"blue": "สีน้ำเงิน",
"green": "สีเขียว",
"yellow": "สีเหลือง",
"Select {{style}} style": "เลือกสไตล์ {{style}}",
"Select {{color}} color": "เลือกสี {{color}}",
"Close Book": "ปิดหนังสือ",
"Speed Reading": "การอ่านเร็ว",
"Close Speed Reading": "ปิดการอ่านเร็ว",
"Authors": "ผู้เขียน",
"Books": "หนังสือ",
"Groups": "กลุ่ม"
}
@@ -975,7 +975,6 @@
"{{count}} book(s) synced_other": "{{count}} kitap senkronize edildi",
"Unable to start RSVP": "RSVP başlatılamadı",
"RSVP not supported for PDF": "PDF için RSVP desteklenmiyor",
"Close RSVP": "RSVP'yi Kapat",
"Select Chapter": "Bölüm Seç",
"{{number}} WPM": "{{number}} Kelime/Dakika",
"Context": "Bağlam",
@@ -1011,10 +1010,25 @@
"Scroll right": "Sağa kaydır",
"Library Sync Progress": "Kütüphane Senkronizasyon İlerlemesi",
"Back to library": "Kütüphaneye dön",
"Manual": "Manuel",
"Group by...": "Şuna göre grupla...",
"Export as Plain Text": "Düz Metin Olarak Dışa Aktar",
"Export as Markdown": "Markdown Olarak Dışa Aktar",
"Show Page Navigation Buttons": "Gezinme düğmeleri",
"Page {{number}}": "Sayfa {{number}}"
"Page {{number}}": "Sayfa {{number}}",
"highlight": "vurgula",
"underline": "altı çizili",
"squiggly": "dalgalı",
"red": "kırmızı",
"violet": "menekşe",
"blue": "mavi",
"green": "yeşil",
"yellow": "sarı",
"Select {{style}} style": "{{style}} stilini seç",
"Select {{color}} color": "{{color}} rengini seç",
"Close Book": "Kitabı Kapat",
"Speed Reading": "Hızlı Okuma",
"Close Speed Reading": "Hızlı Okumayı Kapat",
"Authors": "Yazarlar",
"Books": "Kitaplar",
"Groups": "Gruplar"
}
@@ -999,7 +999,6 @@
"{{count}} book(s) synced_other": "{{count}} книг синхронізовано",
"Unable to start RSVP": "Не вдалося запустити RSVP",
"RSVP not supported for PDF": "RSVP не підтримується для PDF",
"Close RSVP": "Закрити RSVP",
"Select Chapter": "Вибрати розділ",
"{{number}} WPM": "{{number}} WPM",
"Context": "Контекст",
@@ -1035,10 +1034,25 @@
"Scroll right": "Прокрутити вправо",
"Library Sync Progress": "Прогрес синхронізації бібліотеки",
"Back to library": "Назад до бібліотеки",
"Manual": "Вручну",
"Group by...": "Групувати за...",
"Export as Plain Text": "Експортувати як звичайний текст",
"Export as Markdown": "Експортувати як Markdown",
"Show Page Navigation Buttons": "Кнопки навігації",
"Page {{number}}": "Сторінка {{number}}"
"Page {{number}}": "Сторінка {{number}}",
"highlight": "виділення",
"underline": "підкреслення",
"squiggly": "хвиляста лінія",
"red": "червоний",
"violet": "фіолетовий",
"blue": "синій",
"green": "зелений",
"yellow": "жовтий",
"Select {{style}} style": "Вибрати стиль {{style}}",
"Select {{color}} color": "Вибрати колір {{color}}",
"Close Book": "Закрити книгу",
"Speed Reading": "Швидкісне читання",
"Close Speed Reading": "Закрити швидкісне читання",
"Authors": "Автори",
"Books": "Книги",
"Groups": "Групи"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "Đã đồng bộ {{count}} cuốn sách",
"Unable to start RSVP": "Không thể bắt đầu RSVP",
"RSVP not supported for PDF": "RSVP không được hỗ trợ cho PDF",
"Close RSVP": "Đóng RSVP",
"Select Chapter": "Chọn chương",
"{{number}} WPM": "{{number}} WPM",
"Context": "Ngữ cảnh",
@@ -999,10 +998,25 @@
"Scroll right": "Cuộn sang phải",
"Library Sync Progress": "Tiến trình đồng bộ hóa thư viện",
"Back to library": "Quay lại thư viện",
"Manual": "Thủ công",
"Group by...": "Nhóm theo...",
"Export as Plain Text": "Xuất dưới dạng văn bản thuần túy",
"Export as Markdown": "Xuất dưới dạng Markdown",
"Show Page Navigation Buttons": "Nút điều hướng trang",
"Page {{number}}": "Trang {{number}}"
"Page {{number}}": "Trang {{number}}",
"highlight": "làm nổi bật",
"underline": "gạch chân",
"squiggly": "ngoằn ngoèo",
"red": "đỏ",
"violet": "tím",
"blue": "xanh lam",
"green": "xanh lá",
"yellow": "vàng",
"Select {{style}} style": "Chọn kiểu {{style}}",
"Select {{color}} color": "Chọn màu {{color}}",
"Close Book": "Đóng sách",
"Speed Reading": "Đọc nhanh",
"Close Speed Reading": "Đóng đọc nhanh",
"Authors": "Tác giả",
"Books": "Sách",
"Groups": "Nhóm"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "{{count}} 本书已同步",
"Unable to start RSVP": "无法启动 RSVP",
"RSVP not supported for PDF": "PDF 不支持 RSVP",
"Close RSVP": "关闭 RSVP",
"Select Chapter": "选择章节",
"{{number}} WPM": "{{number}} WPM",
"Context": "上下文",
@@ -999,10 +998,25 @@
"Scroll right": "向右滚动",
"Library Sync Progress": "库同步进度",
"Back to library": "返回书库",
"Manual": "手动",
"Group by...": "分组方式...",
"Export as Plain Text": "导出为纯文本",
"Export as Markdown": "导出为 Markdown",
"Show Page Navigation Buttons": "显示翻页按钮",
"Page {{number}}": "第 {{number}} 页"
"Page {{number}}": "第 {{number}} 页",
"highlight": "高亮",
"underline": "下划线",
"squiggly": "波浪线",
"red": "红色",
"violet": "紫色",
"blue": "蓝色",
"green": "绿色",
"yellow": "黄色",
"Select {{style}} style": "选择 {{style}} 样式",
"Select {{color}} color": "选择 {{color}} 颜色",
"Close Book": "关闭书籍",
"Speed Reading": "快速阅读",
"Close Speed Reading": "关闭快速阅读",
"Authors": "作者",
"Books": "书籍",
"Groups": "分组"
}
@@ -963,7 +963,6 @@
"{{count}} book(s) synced_other": "{{count}} 本書已同步",
"Unable to start RSVP": "無法啟動 RSVP",
"RSVP not supported for PDF": "PDF 不支援 RSVP",
"Close RSVP": "關閉 RSVP",
"Select Chapter": "選擇章節",
"{{number}} WPM": "{{number}} WPM",
"Context": "上下文",
@@ -999,10 +998,25 @@
"Scroll right": "向右捲動",
"Library Sync Progress": "資料庫同步進度",
"Back to library": "返回書庫",
"Manual": "手動",
"Group by...": "分組方式...",
"Export as Plain Text": "匯出為純文字",
"Export as Markdown": "匯出為 Markdown",
"Show Page Navigation Buttons": "顯示翻頁按鈕",
"Page {{number}}": "第 {{number}} 頁"
"Page {{number}}": "第 {{number}} 頁",
"highlight": "高亮",
"underline": "底線",
"squiggly": "波浪線",
"red": "紅色",
"violet": "紫色",
"blue": "藍色",
"green": "綠色",
"yellow": "黃色",
"Select {{style}} style": "選擇 {{style}} 樣式",
"Select {{color}} color": "選擇 {{color}} 顏色",
"Close Book": "關閉書籍",
"Speed Reading": "快速閱讀",
"Close Speed Reading": "關閉快速閱讀",
"Authors": "作者",
"Books": "書籍",
"Groups": "分組"
}
@@ -231,16 +231,16 @@ describe('createBookGroups', () => {
});
});
describe('groupBy: manual', () => {
it('should return books as-is (manual mode handled elsewhere)', () => {
describe('groupBy: group', () => {
it('should return books as-is (group mode handled elsewhere)', () => {
const books = [
createMockBook({ hash: '1', title: 'Book 1' }),
createMockBook({ hash: '2', title: 'Book 2' }),
];
const result = createBookGroups(books, LibraryGroupByType.Manual);
const result = createBookGroups(books, LibraryGroupByType.Group);
// Manual mode just returns filtered books - actual grouping is in generateBookshelfItems
// Group mode just returns filtered books - actual grouping is in generateBookshelfItems
expect(result).toHaveLength(2);
});
});
@@ -726,24 +726,22 @@ describe('ensureLibrarySortByType', () => {
describe('ensureLibraryGroupByType', () => {
it('should return valid group type when value is valid', () => {
expect(ensureLibraryGroupByType('none', LibraryGroupByType.Manual)).toBe(
expect(ensureLibraryGroupByType('none', LibraryGroupByType.Group)).toBe(
LibraryGroupByType.None,
);
expect(ensureLibraryGroupByType('manual', LibraryGroupByType.None)).toBe(
LibraryGroupByType.Manual,
expect(ensureLibraryGroupByType('group', LibraryGroupByType.None)).toBe(
LibraryGroupByType.Group,
);
expect(ensureLibraryGroupByType('series', LibraryGroupByType.Manual)).toBe(
expect(ensureLibraryGroupByType('series', LibraryGroupByType.Group)).toBe(
LibraryGroupByType.Series,
);
expect(ensureLibraryGroupByType('author', LibraryGroupByType.Manual)).toBe(
expect(ensureLibraryGroupByType('author', LibraryGroupByType.Group)).toBe(
LibraryGroupByType.Author,
);
});
it('should return fallback when value is null', () => {
expect(ensureLibraryGroupByType(null, LibraryGroupByType.Manual)).toBe(
LibraryGroupByType.Manual,
);
expect(ensureLibraryGroupByType(null, LibraryGroupByType.Group)).toBe(LibraryGroupByType.Group);
});
it('should return fallback when value is undefined', () => {
@@ -753,8 +751,8 @@ describe('ensureLibraryGroupByType', () => {
});
it('should return fallback when value is invalid', () => {
expect(ensureLibraryGroupByType('invalid', LibraryGroupByType.Manual)).toBe(
LibraryGroupByType.Manual,
expect(ensureLibraryGroupByType('invalid', LibraryGroupByType.Group)).toBe(
LibraryGroupByType.Group,
);
expect(ensureLibraryGroupByType('random', LibraryGroupByType.Author)).toBe(
LibraryGroupByType.Author,
@@ -762,7 +760,7 @@ describe('ensureLibraryGroupByType', () => {
});
it('should return fallback when value is empty string', () => {
expect(ensureLibraryGroupByType('', LibraryGroupByType.Manual)).toBe(LibraryGroupByType.Manual);
expect(ensureLibraryGroupByType('', LibraryGroupByType.Group)).toBe(LibraryGroupByType.Group);
});
});
@@ -120,7 +120,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({
if (params.get('sort') === LibrarySortByType.Updated) params.delete('sort');
if (params.get('order') === 'desc') params.delete('order');
if (params.get('groupBy') === LibraryGroupByType.Manual) params.delete('groupBy');
if (params.get('groupBy') === LibraryGroupByType.Group) params.delete('groupBy');
if (params.get('cover') === 'crop') params.delete('cover');
if (params.get('view') === 'grid') params.delete('view');
@@ -140,8 +140,8 @@ const Bookshelf: React.FC<BookshelfProps> = ({
}, [libraryBooks, queryTerm]);
const currentBookshelfItems = useMemo(() => {
if (groupBy === LibraryGroupByType.Manual) {
// Use existing generateBookshelfItems for manual mode
if (groupBy === LibraryGroupByType.Group) {
// Use existing generateBookshelfItems for group mode
const groupName = getGroupName(groupId) || '';
if (groupId && !groupName) {
return [];
@@ -192,7 +192,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({
// Sort ungrouped books - use within-group sorter if we're inside a group
// (for series, this ensures books are sorted by series index)
const bookSorter = createBookSorter(sortBy, uiLanguage);
if (groupId && groupBy !== LibraryGroupByType.Manual && groupBy !== LibraryGroupByType.None) {
if (groupId && groupBy !== LibraryGroupByType.Group && groupBy !== LibraryGroupByType.None) {
ungroupedBooks.sort((a, b) => withinGroupSorter(a, b) * sortOrderMultiplier);
} else {
ungroupedBooks.sort((a, b) => bookSorter(a, b) * sortOrderMultiplier);
@@ -45,10 +45,10 @@ const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
];
const groupByOptions = [
{ label: _('None'), value: LibraryGroupByType.None },
{ label: _('Manual'), value: LibraryGroupByType.Manual },
{ label: _('Authors'), value: LibraryGroupByType.Author },
{ label: _('Books'), value: LibraryGroupByType.None },
{ label: _('Groups'), value: LibraryGroupByType.Group },
{ label: _('Series'), value: LibraryGroupByType.Series },
{ label: _('Author'), value: LibraryGroupByType.Author },
];
const sortByOptions = [
@@ -95,7 +95,7 @@ const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
await saveSysSettings(envConfig, 'libraryGroupBy', value);
const params = new URLSearchParams(searchParams?.toString());
if (value === LibraryGroupByType.Manual) {
if (value === LibraryGroupByType.Group) {
params.delete('groupBy');
} else {
params.set('groupBy', value);
@@ -182,7 +182,7 @@ export const createBookGroups = (
return createAuthorGroups(activeBooks);
}
// 'manual' mode is handled separately by generateBookshelfItems
// 'group' mode is handled separately by generateBookshelfItems
return activeBooks;
};
@@ -56,7 +56,7 @@ import { useBookCoverAutoSave } from '../hooks/useAutoSaveBookCover';
import { useDiscordPresence } from '@/hooks/useDiscordPresence';
import { manageSyntaxHighlighting } from '@/utils/highlightjs';
import { getViewInsets } from '@/utils/insets';
import { handleAccessibilityEvents } from '@/utils/a11y';
import { handleA11yNavigation } from '@/utils/a11y';
import { isCJKLang } from '@/utils/lang';
import { getLocale } from '@/utils/misc';
import Spinner from '@/components/Spinner';
@@ -214,7 +214,7 @@ const FoliateViewer: React.FC<{
applyThemeModeClass(detail.doc, isDarkMode);
applyScrollModeClass(detail.doc, viewSettings.scrolled || false);
keepTextAlignment(detail.doc);
handleAccessibilityEvents(viewRef.current, detail.doc, detail.index);
handleA11yNavigation(viewRef.current, detail.doc, detail.index);
// Inline scripts in tauri platforms are not executed by default
if (viewSettings.allowScript && isTauriAppPlatform()) {
@@ -246,6 +246,7 @@ const HeaderBar: React.FC<HeaderBarProps> = ({
headerRef={headerRef}
showMinimize={bookKeys.length == 1 && windowButtonVisible}
showMaximize={bookKeys.length == 1 && windowButtonVisible}
closeButtonLabel={_('Close Book')}
onClose={() => {
setHoveredBookKey(null);
onCloseBook(bookKey);
@@ -28,6 +28,7 @@ const AnnotationToolButton: React.FC<AnnotationToolButtonProps> = ({
>
<button
onClick={handleClick}
aria-label={tooltipText}
className={clsx(
'flex h-8 min-h-8 w-8 items-center justify-center p-0',
disabled
@@ -4,12 +4,20 @@ import { FaCheckCircle } from 'react-icons/fa';
import { HighlightColor, HighlightStyle } from '@/types/book';
import { useEnv } from '@/context/EnvContext';
import { useThemeStore } from '@/store/themeStore';
import { useTranslation } from '@/hooks/useTranslation';
import { useSettingsStore } from '@/store/settingsStore';
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
import { saveSysSettings } from '@/helpers/settings';
import { stubTranslation as _ } from '@/utils/misc';
const styles = ['highlight', 'underline', 'squiggly'] as HighlightStyle[];
const defaultColors = ['red', 'violet', 'blue', 'green', 'yellow'] as HighlightColor[];
const styles = [_('highlight'), _('underline'), _('squiggly')] as HighlightStyle[];
const defaultColors = [
_('red'),
_('violet'),
_('blue'),
_('green'),
_('yellow'),
] as HighlightColor[];
const getColorHex = (
customColors: Record<HighlightColor, string>,
@@ -41,6 +49,7 @@ const HighlightOptions: React.FC<HighlightOptionsProps> = ({
selectedColor: _selectedColor,
onHandleHighlight,
}) => {
const _ = useTranslation();
const { envConfig } = useEnv();
const { settings } = useSettingsStore();
const { isDarkMode } = useThemeStore();
@@ -109,6 +118,7 @@ const HighlightOptions: React.FC<HighlightOptionsProps> = ({
{styles.map((style) => (
<button
key={style}
aria-label={_('Select {{style}} style', { style: _(style) })}
onClick={() => handleSelectStyle(style)}
className='not-eink:bg-gray-700 eink-bordered flex items-center justify-center rounded-full p-0'
style={{ width: size28, height: size28, minHeight: size28 }}
@@ -169,6 +179,7 @@ const HighlightOptions: React.FC<HighlightOptionsProps> = ({
<div key={color} className='flex items-center justify-center'>
<button
key={color}
aria-label={_('Select {{color}} color', { color: _(color) })}
onClick={() => handleSelectColor(color)}
style={{
width: size16,
@@ -290,7 +290,7 @@ const RSVPOverlay: React.FC<RSVPOverlayProps> = ({
return (
<div
data-testid='rsvp-overlay'
aria-label={_('RSVP Speed Reading Overlay')}
aria-label={_('Speed Reading')}
className='fixed inset-0 z-[10000] flex select-none flex-col'
style={{
backgroundColor: bgColor,
@@ -308,7 +308,7 @@ const RSVPOverlay: React.FC<RSVPOverlayProps> = ({
{/* Header */}
<div className='rsvp-header flex shrink-0 items-center justify-between gap-2 p-3 md:gap-4 md:p-4'>
<button
aria-label={_('Close RSVP')}
aria-label={_('Close Speed Reading')}
className='flex h-10 w-10 shrink-0 cursor-pointer items-center justify-center rounded-full border-none bg-transparent transition-colors hover:bg-gray-500/20 md:h-11 md:w-11'
onClick={onClose}
title={_('Close')}
+6 -3
View File
@@ -46,6 +46,7 @@ const MenuItem: React.FC<MenuItemProps> = ({
}) => {
const _ = useTranslation();
const iconSize = useResponsiveSize(16);
const [isDetailsOpen, setIsDetailsOpen] = React.useState(detailsOpen);
const IconType = Icon || (toggled !== undefined ? (toggled ? MdCheck : undefined) : undefined);
const handleClick = () => {
@@ -105,11 +106,13 @@ const MenuItem: React.FC<MenuItemProps> = ({
if (children) {
return (
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
<ul className='menu rounded-box m-0 p-0' role='menuitem' tabIndex={-1}>
<ul className='menu rounded-box m-0 p-0'>
<li aria-label={label}>
<details open={detailsOpen}>
<details open={detailsOpen} onToggle={(e) => setIsDetailsOpen(e.currentTarget.open)}>
<summary
role='button'
tabIndex={-1}
aria-expanded={isDetailsOpen}
className={clsx(
'hover:bg-base-300 text-base-content cursor-pointer rounded-md p-1 py-[10px] pr-3',
disabled && 'btn-disabled cursor-not-allowed text-gray-400',
@@ -12,6 +12,7 @@ interface WindowButtonsProps {
showMinimize?: boolean;
showMaximize?: boolean;
showClose?: boolean;
closeButtonLabel?: string;
onMinimize?: () => void;
onToggleMaximize?: () => void;
onClose?: () => void;
@@ -41,6 +42,7 @@ const WindowButtons: React.FC<WindowButtonsProps> = ({
showMinimize = true,
showMaximize = true,
showClose = true,
closeButtonLabel,
onMinimize,
onToggleMaximize,
onClose,
@@ -218,7 +220,11 @@ const WindowButtons: React.FC<WindowButtonsProps> = ({
)}
{showClose && (appService?.hasWindowBar || onClose) && (
<WindowButton onClick={handleClose} label={_('Close')} id='titlebar-close'>
<WindowButton
onClick={handleClose}
label={closeButtonLabel || _('Close')}
id='titlebar-close'
>
<svg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' viewBox='0 0 24 24'>
<path
fill='currentColor'
+1 -1
View File
@@ -83,7 +83,7 @@ export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
libraryViewMode: 'grid',
librarySortBy: LibrarySortByType.Updated,
librarySortAscending: false,
libraryGroupBy: LibraryGroupByType.Manual,
libraryGroupBy: LibraryGroupByType.Group,
libraryCoverFit: 'crop',
libraryAutoColumns: true,
libraryColumns: 6,
+1 -1
View File
@@ -24,7 +24,7 @@ export type LibraryCoverFitType = 'crop' | 'fit';
export const LibraryGroupByType = {
None: 'none',
Manual: 'manual',
Group: 'group',
Series: 'series',
Author: 'author',
} as const;
+5 -2
View File
@@ -6,6 +6,8 @@ import { LocaleWithTextInfo } from './misc';
export const NOTE_PREFIX = 'foliate-note:';
type RangeAnchor = (doc: Document) => Range;
export interface FoliateView extends HTMLElement {
open: (book: BookDoc) => Promise<void>;
close: () => void;
@@ -20,7 +22,8 @@ export interface FoliateView extends HTMLElement {
goLeft: () => void;
goRight: () => void;
getCFI: (index: number, range: Range) => string;
resolveCFI: (cfi: string) => { index: number; anchor: (doc: Document) => Range };
resolveCFI: (cfi: string) => { index: number; anchor: RangeAnchor };
resolveNavigation: (cfiOrHref: string) => { index: number; anchor?: RangeAnchor };
addAnnotation: (
note: BookNote & { value?: string },
remove?: boolean,
@@ -66,7 +69,7 @@ export interface FoliateView extends HTMLElement {
prev: () => Promise<void>;
nextSection?: () => Promise<void>;
prevSection?: () => Promise<void>;
goTo?: (params: { index: number; anchor: number }) => void;
goTo?: (params: { index: number; anchor?: number | RangeAnchor }) => void;
setStyles?: (css: string) => void;
getContents: () => { doc: Document; index?: number; overlayer?: unknown }[];
scrollToAnchor: (anchor: number | Range) => void;
+48 -10
View File
@@ -1,20 +1,58 @@
import { FoliateView } from '@/types/view';
export const handleAccessibilityEvents = (
export const handleA11yNavigation = (
view: FoliateView | null,
document: Document,
index: number,
) => {
if (!view) return;
document.querySelectorAll('a, p').forEach((el) => {
const state = {
skipInitial: true,
hasRecentRelocate: false,
relocateTimer: null as ReturnType<typeof setTimeout> | null,
};
const markRelocated = () => {
state.hasRecentRelocate = true;
if (state.relocateTimer) clearTimeout(state.relocateTimer);
state.relocateTimer = setTimeout(() => {
state.hasRecentRelocate = false;
}, 1000);
};
view.renderer.addEventListener('relocate', markRelocated);
const observer = new IntersectionObserver(
(entries) => {
if (state.skipInitial) {
state.skipInitial = false;
return;
}
if (state.hasRecentRelocate) return;
for (const entry of entries) {
if (entry.isIntersecting) {
const range = document.createRange();
range.selectNodeContents(entry.target);
const cfi = view.getCFI(index, range);
setTimeout(() => {
if (state.hasRecentRelocate) return;
const resolved = view.resolveNavigation(cfi);
view.renderer.goTo?.(resolved);
console.log('Navigating to new location from screen reader');
}, 500);
break;
}
}
},
{ threshold: 0 },
);
document.querySelectorAll('a').forEach((el) => {
el.setAttribute('tabindex', '-1');
el.addEventListener('focus', (e) => {
const range = document.createRange();
range.selectNodeContents(e.target as Node);
const cfi = view.getCFI(index, range);
setTimeout(() => {
view.goTo(cfi);
}, 100);
});
});
document.querySelectorAll('p').forEach((el) => {
observer.observe(el);
});
};