feat(reader): custom hardware-button page turning (#4177)
* feat(reader): add custom hardware-button page turning (#4139) Lets users bind hardware remote keys (media keys, D-pad/arrow keys) to previous/next page via a learn-mode capture UI in reader settings — an accessibility feature for page-turner remotes. - New global hardwarePageTurner system setting (enabled + key bindings). - hardwareKeys.ts: key normalization, matching, and page-turn resolution. - deviceStore: reference-counted media-key interception + learn mode. - usePagination: flips pages from bound media keys (native bridge) and D-pad/keyboard keys (DOM keydown), scoped to the active book and suppressed while the toolbar is visible. - Page Turner settings section on all platforms; web/desktop bind keys via DOM keydown only, native media-key interception stays mobile-only. - Android: intercept media + learn-mode keys in dispatchKeyEvent. - iOS: forward media keys via MPRemoteCommandCenter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(i18n): add and translate hardware page turner strings (#4139) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(reader): refine hardware page turner (#4139) - Handle book-iframe key events (iframe-keydown messages) so custom bindings work as soon as a book is open, not only after the settings panel has been shown. - Add Previous/Next Section bindings alongside the page bindings. - Rename the hardwareKeys util to keybinding. - Wire the Page Turner section into the settings Reset action. - Drop the focus ring on the capture buttons; BoxedList gains an optional description. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(i18n): translate page turner section and key strings (#4139) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -227,7 +227,6 @@
|
||||
"CJK Font": "خط CJK",
|
||||
"Clear Search": "مسح البحث",
|
||||
"Header & Footer": "الترويسة والتذييل",
|
||||
"Apply also in Scrolled Mode": "تطبيق أيضًا في وضع التمرير",
|
||||
"A new version of Readest is available!": "يتوفر إصدار جديد من Readest!",
|
||||
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "إصدار {{newVersion}} من ريديست متاح للتنزيل (الإصدار المثبت حاليًا {{currentVersion}}).",
|
||||
"Download and install now?": "هل ترغب في تنزيله وتثبيته الآن؟",
|
||||
@@ -251,7 +250,6 @@
|
||||
"Grid": "شبكة",
|
||||
"(from 'As You Like It', Act II)": "(من 'كما تحب'، الفصل الثاني)",
|
||||
"Link Color": "لون الرابط",
|
||||
"Volume Keys for Page Flip": "مفاتيح الصوت لتقليب الصفحات",
|
||||
"Screen": "الشاشة",
|
||||
"Orientation": "الاتجاه",
|
||||
"Portrait": "عمودي",
|
||||
@@ -1512,5 +1510,27 @@
|
||||
"Start your library": "ابدأ مكتبتك",
|
||||
"Pick a book from your device to add it to your library.": "اختر كتابًا من جهازك لإضافته إلى مكتبتك.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "أفلِت كتابًا في أي مكان على هذه النافذة، أو اختر واحدًا من حاسوبك.",
|
||||
"Sign in to sync your library": "سجّل الدخول لمزامنة مكتبتك"
|
||||
"Sign in to sync your library": "سجّل الدخول لمزامنة مكتبتك",
|
||||
"Clear": "مسح",
|
||||
"Listening…": "يستمع…",
|
||||
"Set key": "تعيين مفتاح",
|
||||
"Page Turner": "قالب الصفحات",
|
||||
"Media Next": "وسائط التالي",
|
||||
"Media Previous": "وسائط السابق",
|
||||
"Media Play/Pause": "وسائط تشغيل/إيقاف مؤقت",
|
||||
"Media Fast Forward": "وسائط تقديم سريع",
|
||||
"Media Rewind": "وسائط إرجاع",
|
||||
"Volume Up": "رفع الصوت",
|
||||
"Volume Down": "خفض الصوت",
|
||||
"Arrow Left": "سهم يسار",
|
||||
"Arrow Right": "سهم يمين",
|
||||
"Arrow Up": "سهم أعلى",
|
||||
"Arrow Down": "سهم أسفل",
|
||||
"Page Up": "صفحة للأعلى",
|
||||
"Page Down": "صفحة للأسفل",
|
||||
"Space": "مسافة",
|
||||
"Enter": "إدخال",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "اضغط على زر في جهاز التحكم عن بُعد أو لوحة المفاتيح بعد النقر على \"تعيين مفتاح\".",
|
||||
"Use Volume Keys": "استخدام مفاتيح الصوت",
|
||||
"Custom Page Turner": "قلّاب الصفحات المخصص"
|
||||
}
|
||||
|
||||
@@ -195,7 +195,6 @@
|
||||
"Scrolled Mode": "স্ক্রল মোড",
|
||||
"Overlap Pixels": "ওভারল্যাপ পিক্সেল",
|
||||
"Disable Double Click": "ডাবল ক্লিক নিষ্ক্রিয়",
|
||||
"Volume Keys for Page Flip": "পৃষ্ঠা উল্টানোর জন্য ভলিউম কী",
|
||||
"Animation": "অ্যানিমেশন",
|
||||
"Paging Animation": "পৃষ্ঠা অ্যানিমেশন",
|
||||
"Security": "নিরাপত্তা",
|
||||
@@ -269,7 +268,6 @@
|
||||
"Reading Progress Style": "পড়ার অগ্রগতির স্টাইল",
|
||||
"Page Number": "পৃষ্ঠা নম্বর",
|
||||
"Percentage": "শতাংশ",
|
||||
"Apply also in Scrolled Mode": "স্ক্রল মোডেও প্রয়োগ করুন",
|
||||
"Screen": "স্ক্রিন",
|
||||
"Orientation": "দিকবিন্যাস",
|
||||
"Portrait": "পোর্ট্রেট",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "আপনার লাইব্রেরি শুরু করুন",
|
||||
"Pick a book from your device to add it to your library.": "আপনার লাইব্রেরিতে যোগ করতে ডিভাইস থেকে একটি বই বেছে নিন।",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "এই উইন্ডোর যেকোনো জায়গায় একটি বই ছাড়ুন, অথবা আপনার কম্পিউটার থেকে একটি বেছে নিন।",
|
||||
"Sign in to sync your library": "আপনার লাইব্রেরি সিঙ্ক করতে সাইন ইন করুন"
|
||||
"Sign in to sync your library": "আপনার লাইব্রেরি সিঙ্ক করতে সাইন ইন করুন",
|
||||
"Clear": "মুছুন",
|
||||
"Listening…": "শুনছে…",
|
||||
"Set key": "কী সেট করুন",
|
||||
"Page Turner": "পেজ টার্নার",
|
||||
"Media Next": "মিডিয়া পরবর্তী",
|
||||
"Media Previous": "মিডিয়া পূর্ববর্তী",
|
||||
"Media Play/Pause": "মিডিয়া প্লে/পজ",
|
||||
"Media Fast Forward": "মিডিয়া ফাস্ট ফরওয়ার্ড",
|
||||
"Media Rewind": "মিডিয়া রিওয়াইন্ড",
|
||||
"Volume Up": "ভলিউম বাড়ান",
|
||||
"Volume Down": "ভলিউম কমান",
|
||||
"Arrow Left": "বাম তীর",
|
||||
"Arrow Right": "ডান তীর",
|
||||
"Arrow Up": "উপরের তীর",
|
||||
"Arrow Down": "নিচের তীর",
|
||||
"Page Up": "পেজ আপ",
|
||||
"Page Down": "পেজ ডাউন",
|
||||
"Space": "স্পেস",
|
||||
"Enter": "এন্টার",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"কী সেট করুন\" ট্যাপ করার পর আপনার রিমোট কন্ট্রোলার বা কীবোর্ডের একটি বোতাম চাপুন।",
|
||||
"Use Volume Keys": "ভলিউম কী ব্যবহার করুন",
|
||||
"Custom Page Turner": "কাস্টম পেজ টার্নার"
|
||||
}
|
||||
|
||||
@@ -227,7 +227,6 @@
|
||||
"CJK Font": "རྒྱ་ཡིག་གི་ཡིག་གཟུགས།",
|
||||
"Clear Search": "འཚོལ་བཤེར་བསལ་བ།",
|
||||
"Header & Footer": "ཤོག་ངོས་ཀྱི་མགོ་དང་མཇུག",
|
||||
"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?": "ད་ལྟ་ཕབ་ལེན་དང་བསྒྲིགས་དགོས་སམ།",
|
||||
@@ -251,7 +250,6 @@
|
||||
"Grid": "དྲྭ་རྡལ།",
|
||||
"(from 'As You Like It', Act II)": "《ཐམས་ཅད་དགའ་བ》ནས་དྲངས་པ། ལེའུ་གཉིས་པ།",
|
||||
"Link Color": "སྦྲེལ་ཐག་གི་ཚོན་མདོག",
|
||||
"Volume Keys for Page Flip": "སྒྲ་ཚད་ལྡེ་མིག་གིས་ཤོག་ལྷེ་བསྒྱུར་བ།",
|
||||
"Screen": "བརྡ་ཁྱབ་ངོས།",
|
||||
"Orientation": "བརྡ་ཁྱབ་ངོས་ཀྱི་ཁ་ཕྱོགས།",
|
||||
"Portrait": "ཀྲིང་ངོས།",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "ཁྱེད་ཀྱི་དཔེ་མཛོད་འགོ་འཛུགས།",
|
||||
"Pick a book from your device to add it to your library.": "ཁྱེད་ཀྱི་སྒྲིག་ཆས་ནས་དཔེ་དེབ་ཅིག་འདེམས་ནས་ཁྱེད་ཀྱི་དཔེ་མཛོད་ལ་ཁ་སྣོན་གྱིས།",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "སྒེའུ་ཁུང་འདིའི་གང་སར་དཔེ་དེབ་ཅིག་འཇོག་པའམ་ཡང་ན་ཁྱེད་ཀྱི་གློག་ཀླད་ནས་འདེམས་རོགས།",
|
||||
"Sign in to sync your library": "ཁྱེད་ཀྱི་དཔེ་མཛོད་མཉམ་སྦྱོར་གྱི་ཆེད་ནང་བསྐྱོད་གནང་རོགས།"
|
||||
"Sign in to sync your library": "ཁྱེད་ཀྱི་དཔེ་མཛོད་མཉམ་སྦྱོར་གྱི་ཆེད་ནང་བསྐྱོད་གནང་རོགས།",
|
||||
"Clear": "སུབ་པ།",
|
||||
"Listening…": "ཉན་གྱི་ཡོད…",
|
||||
"Set key": "མཐེབ་གཞི་གཏན་འཁེལ།",
|
||||
"Page Turner": "ཤོག་གྲུ་འཕར་མཁན།",
|
||||
"Media Next": "མི་ཡིའི་རྗེས་མ།",
|
||||
"Media Previous": "མི་ཡིའི་སྔོན་མ།",
|
||||
"Media Play/Pause": "མི་ཡི་བཏང་/བཀག",
|
||||
"Media Fast Forward": "མི་ཡི་མྱུར་མགྱོགས་སྔར་བསྐྱོད།",
|
||||
"Media Rewind": "མི་ཡི་ཕྱིར་བསྐྱོད།",
|
||||
"Volume Up": "སྒྲ་སྐད་མཐོར་གཏོང་།",
|
||||
"Volume Down": "སྒྲ་སྐད་དམའར་གཏོང་།",
|
||||
"Arrow Left": "གཡོན་མདའ།",
|
||||
"Arrow Right": "གཡས་མདའ།",
|
||||
"Arrow Up": "ཡར་མདའ།",
|
||||
"Arrow Down": "མར་མདའ།",
|
||||
"Page Up": "ཤོག་ལྷེ་ཡར།",
|
||||
"Page Down": "ཤོག་ལྷེ་མར།",
|
||||
"Space": "བར་ཐག",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"མཐེབ་གཞི་གཏན་འཁེལ།\" ལ་རེག་རྗེས། ཁྱེད་ཀྱི་རྒྱང་འཐེན་སྒྲིག་ཆས་སམ་མཐེབ་གཞི་གང་རུང་གི་ཐོག་མཐེབ་གཅིག་གནོན་རོགས།",
|
||||
"Use Volume Keys": "སྒྲ་སྐད་མཐེབ་གཞི་སྤྱོད་པ།",
|
||||
"Custom Page Turner": "རང་སྒྲུབ་ཤོག་ལྷེ་སྤོ་བའི་ལམ་ལུགས།"
|
||||
}
|
||||
|
||||
@@ -227,7 +227,6 @@
|
||||
"CJK Font": "CJK-Schriftart",
|
||||
"Clear Search": "Suche löschen",
|
||||
"Header & Footer": "Kopf- & Fußzeile",
|
||||
"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?",
|
||||
@@ -251,7 +250,6 @@
|
||||
"Grid": "Raster",
|
||||
"(from 'As You Like It', Act II)": "(aus 'Wie es euch gefällt', Akt II)",
|
||||
"Link Color": "Linkfarbe",
|
||||
"Volume Keys for Page Flip": "Volumen-Tasten für Seitenwechsel",
|
||||
"Screen": "Bildschirm",
|
||||
"Orientation": "Orientierung",
|
||||
"Portrait": "Hochformat",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "Starten Sie Ihre Bibliothek",
|
||||
"Pick a book from your device to add it to your library.": "Wählen Sie ein Buch von Ihrem Gerät, um es Ihrer Bibliothek hinzuzufügen.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Ziehen Sie ein Buch an eine beliebige Stelle dieses Fensters oder wählen Sie eines von Ihrem Computer aus.",
|
||||
"Sign in to sync your library": "Melden Sie sich an, um Ihre Bibliothek zu synchronisieren"
|
||||
"Sign in to sync your library": "Melden Sie sich an, um Ihre Bibliothek zu synchronisieren",
|
||||
"Clear": "Löschen",
|
||||
"Listening…": "Warte auf Eingabe…",
|
||||
"Set key": "Taste festlegen",
|
||||
"Page Turner": "Seitenblätterer",
|
||||
"Media Next": "Medien: Weiter",
|
||||
"Media Previous": "Medien: Zurück",
|
||||
"Media Play/Pause": "Medien: Wiedergabe/Pause",
|
||||
"Media Fast Forward": "Medien: Schnellvorlauf",
|
||||
"Media Rewind": "Medien: Rücklauf",
|
||||
"Volume Up": "Lautstärke erhöhen",
|
||||
"Volume Down": "Lautstärke verringern",
|
||||
"Arrow Left": "Pfeil links",
|
||||
"Arrow Right": "Pfeil rechts",
|
||||
"Arrow Up": "Pfeil hoch",
|
||||
"Arrow Down": "Pfeil runter",
|
||||
"Page Up": "Bild auf",
|
||||
"Page Down": "Bild ab",
|
||||
"Space": "Leertaste",
|
||||
"Enter": "Eingabe",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Drücken Sie eine Taste auf Ihrer Fernbedienung oder Tastatur, nachdem Sie auf \"Taste festlegen\" getippt haben.",
|
||||
"Use Volume Keys": "Lautstärketasten verwenden",
|
||||
"Custom Page Turner": "Benutzerdefinierter Seitenumblätterer"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "Γραμματοσειρά CJK",
|
||||
"Clear Search": "Καθαρισμός αναζήτησης",
|
||||
"Header & Footer": "Κεφαλίδα & Υποσέλιδο",
|
||||
"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?": "Θέλετε να την κατεβάσετε και να την εγκαταστήσετε τώρα;",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Πλέγμα",
|
||||
"(from 'As You Like It', Act II)": "('Όπως σας αρέσει', Πράξη II)",
|
||||
"Link Color": "Χρώμα συνδέσμου",
|
||||
"Volume Keys for Page Flip": "Ανατροπή με πλήκτρα έντασης",
|
||||
"Screen": "Οθόνη",
|
||||
"Orientation": "Προσανατολισμός",
|
||||
"Portrait": "Πορτραίτο",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "Ξεκινήστε τη βιβλιοθήκη σας",
|
||||
"Pick a book from your device to add it to your library.": "Επιλέξτε ένα βιβλίο από τη συσκευή σας για να το προσθέσετε στη βιβλιοθήκη σας.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Αφήστε ένα βιβλίο οπουδήποτε σε αυτό το παράθυρο ή επιλέξτε ένα από τον υπολογιστή σας.",
|
||||
"Sign in to sync your library": "Συνδεθείτε για να συγχρονίσετε τη βιβλιοθήκη σας"
|
||||
"Sign in to sync your library": "Συνδεθείτε για να συγχρονίσετε τη βιβλιοθήκη σας",
|
||||
"Clear": "Εκκαθάριση",
|
||||
"Listening…": "Αναμονή…",
|
||||
"Set key": "Ορισμός πλήκτρου",
|
||||
"Page Turner": "Στροφέας σελίδων",
|
||||
"Media Next": "Πολυμέσα: Επόμενο",
|
||||
"Media Previous": "Πολυμέσα: Προηγούμενο",
|
||||
"Media Play/Pause": "Πολυμέσα: Αναπαραγωγή/Παύση",
|
||||
"Media Fast Forward": "Πολυμέσα: Γρήγορη προώθηση",
|
||||
"Media Rewind": "Πολυμέσα: Επαναφορά",
|
||||
"Volume Up": "Αύξηση έντασης",
|
||||
"Volume Down": "Μείωση έντασης",
|
||||
"Arrow Left": "Βέλος αριστερά",
|
||||
"Arrow Right": "Βέλος δεξιά",
|
||||
"Arrow Up": "Βέλος πάνω",
|
||||
"Arrow Down": "Βέλος κάτω",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Κενό",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Πατήστε ένα κουμπί στο τηλεχειριστήριο ή το πληκτρολόγιό σας αφού πατήσετε «Ορισμός πλήκτρου».",
|
||||
"Use Volume Keys": "Χρήση πλήκτρων έντασης",
|
||||
"Custom Page Turner": "Προσαρμοσμένος αναλτήρας σελίδων"
|
||||
}
|
||||
|
||||
@@ -250,7 +250,6 @@
|
||||
"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",
|
||||
"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?",
|
||||
@@ -274,7 +273,6 @@
|
||||
"Grid": "Cuadrícula",
|
||||
"(from 'As You Like It', Act II)": "(de 'Como gustéis', Acto II)",
|
||||
"Link Color": "Color del enlace",
|
||||
"Volume Keys for Page Flip": "Botones de volumen para pasar página",
|
||||
"Screen": "Pantalla",
|
||||
"Orientation": "Orientación",
|
||||
"Portrait": "Vertical",
|
||||
@@ -1437,5 +1435,27 @@
|
||||
"Start your library": "Empieza tu biblioteca",
|
||||
"Pick a book from your device to add it to your library.": "Elige un libro de tu dispositivo para añadirlo a tu biblioteca.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Suelta un libro en cualquier parte de esta ventana o elige uno desde tu computadora.",
|
||||
"Sign in to sync your library": "Inicia sesión para sincronizar tu biblioteca"
|
||||
"Sign in to sync your library": "Inicia sesión para sincronizar tu biblioteca",
|
||||
"Clear": "Borrar",
|
||||
"Listening…": "Escuchando…",
|
||||
"Set key": "Asignar tecla",
|
||||
"Page Turner": "Pasador de páginas",
|
||||
"Media Next": "Multimedia: Siguiente",
|
||||
"Media Previous": "Multimedia: Anterior",
|
||||
"Media Play/Pause": "Multimedia: Reproducir/Pausa",
|
||||
"Media Fast Forward": "Multimedia: Avance rápido",
|
||||
"Media Rewind": "Multimedia: Retroceso",
|
||||
"Volume Up": "Subir volumen",
|
||||
"Volume Down": "Bajar volumen",
|
||||
"Arrow Left": "Flecha izquierda",
|
||||
"Arrow Right": "Flecha derecha",
|
||||
"Arrow Up": "Flecha arriba",
|
||||
"Arrow Down": "Flecha abajo",
|
||||
"Page Up": "Re Pág",
|
||||
"Page Down": "Av Pág",
|
||||
"Space": "Espacio",
|
||||
"Enter": "Intro",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Pulse un botón en su mando a distancia o teclado después de tocar \"Asignar tecla\".",
|
||||
"Use Volume Keys": "Usar teclas de volumen",
|
||||
"Custom Page Turner": "Pasador de páginas personalizado"
|
||||
}
|
||||
|
||||
@@ -227,7 +227,6 @@
|
||||
"CJK Font": "فونت CJK",
|
||||
"Clear Search": "پاک کردن جستجو",
|
||||
"Header & Footer": "سربرگ و پاورقی",
|
||||
"Apply also in Scrolled Mode": "همچنین در حالت پیمایشی اِعمال شود",
|
||||
"A new version of Readest is available!": "نسخهی جدیدی از Readest در دسترس است!",
|
||||
"Readest {{newVersion}} is available (installed version {{currentVersion}}).": "نسخهی {{newVersion}} Readest در دسترس است (نسخهی نصبشده: {{currentVersion}}).",
|
||||
"Download and install now?": "الان دانلود و نصب شود؟",
|
||||
@@ -251,7 +250,6 @@
|
||||
"Grid": "جدول",
|
||||
"(from 'As You Like It', Act II)": "(از «همانطور که دوست دارید»، پردهی دوم)",
|
||||
"Link Color": "رنگ لینک",
|
||||
"Volume Keys for Page Flip": "استفاده از کلیدهای صدا برای ورق زدن صفحه",
|
||||
"Screen": "صفحه",
|
||||
"Orientation": "جهت",
|
||||
"Portrait": "عمودی",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "کتابخانهی خود را آغاز کنید",
|
||||
"Pick a book from your device to add it to your library.": "از دستگاه خود کتابی انتخاب کنید تا به کتابخانهتان افزوده شود.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "کتابی را در هر جای این پنجره رها کنید، یا یکی را از رایانهی خود انتخاب کنید.",
|
||||
"Sign in to sync your library": "برای همگامسازی کتابخانهی خود وارد شوید"
|
||||
"Sign in to sync your library": "برای همگامسازی کتابخانهی خود وارد شوید",
|
||||
"Clear": "پاک کردن",
|
||||
"Listening…": "در حال گوش دادن…",
|
||||
"Set key": "تنظیم کلید",
|
||||
"Page Turner": "ورقزن صفحه",
|
||||
"Media Next": "رسانه: بعدی",
|
||||
"Media Previous": "رسانه: قبلی",
|
||||
"Media Play/Pause": "رسانه: پخش/مکث",
|
||||
"Media Fast Forward": "رسانه: جلو بردن سریع",
|
||||
"Media Rewind": "رسانه: برگشت سریع",
|
||||
"Volume Up": "افزایش صدا",
|
||||
"Volume Down": "کاهش صدا",
|
||||
"Arrow Left": "فلش چپ",
|
||||
"Arrow Right": "فلش راست",
|
||||
"Arrow Up": "فلش بالا",
|
||||
"Arrow Down": "فلش پایین",
|
||||
"Page Up": "صفحه بالا",
|
||||
"Page Down": "صفحه پایین",
|
||||
"Space": "فاصله",
|
||||
"Enter": "اینتر",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "پس از ضربه زدن به «تنظیم کلید»، دکمهای روی کنترلر یا صفحهکلید خود فشار دهید.",
|
||||
"Use Volume Keys": "استفاده از کلیدهای صدا",
|
||||
"Custom Page Turner": "صفحهگردان سفارشی"
|
||||
}
|
||||
|
||||
@@ -227,7 +227,6 @@
|
||||
"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",
|
||||
"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 ?",
|
||||
@@ -251,7 +250,6 @@
|
||||
"Grid": "Grille",
|
||||
"(from 'As You Like It', Act II)": "(de 'Comme il vous plaira', Acte II)",
|
||||
"Link Color": "Couleur du lien",
|
||||
"Volume Keys for Page Flip": "Boutons volume pour tourner la page",
|
||||
"Screen": "Écran",
|
||||
"Orientation": "Orientation",
|
||||
"Portrait": "Portrait",
|
||||
@@ -1437,5 +1435,27 @@
|
||||
"Start your library": "Commencez votre bibliothèque",
|
||||
"Pick a book from your device to add it to your library.": "Choisissez un livre depuis votre appareil à ajouter à votre bibliothèque.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Déposez un livre n'importe où sur cette fenêtre, ou choisissez-en un depuis votre ordinateur.",
|
||||
"Sign in to sync your library": "Connectez-vous pour synchroniser votre bibliothèque"
|
||||
"Sign in to sync your library": "Connectez-vous pour synchroniser votre bibliothèque",
|
||||
"Clear": "Effacer",
|
||||
"Listening…": "En attente…",
|
||||
"Set key": "Définir la touche",
|
||||
"Page Turner": "Tourne-page",
|
||||
"Media Next": "Média : Suivant",
|
||||
"Media Previous": "Média : Précédent",
|
||||
"Media Play/Pause": "Média : Lecture/Pause",
|
||||
"Media Fast Forward": "Média : Avance rapide",
|
||||
"Media Rewind": "Média : Retour arrière",
|
||||
"Volume Up": "Volume +",
|
||||
"Volume Down": "Volume -",
|
||||
"Arrow Left": "Flèche gauche",
|
||||
"Arrow Right": "Flèche droite",
|
||||
"Arrow Up": "Flèche haut",
|
||||
"Arrow Down": "Flèche bas",
|
||||
"Page Up": "Page préc.",
|
||||
"Page Down": "Page suiv.",
|
||||
"Space": "Espace",
|
||||
"Enter": "Entrée",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Appuyez sur un bouton de votre télécommande ou de votre clavier après avoir appuyé sur « Définir la touche ».",
|
||||
"Use Volume Keys": "Utiliser les touches de volume",
|
||||
"Custom Page Turner": "Tourne-page personnalisé"
|
||||
}
|
||||
|
||||
@@ -850,7 +850,6 @@
|
||||
"Swap Click Sides": "החלף צדדי לחיצה",
|
||||
"Disable Double Tap": "השבת הקשה כפולה",
|
||||
"Disable Double Click": "השבת לחיצה כפולה",
|
||||
"Volume Keys for Page Flip": "מקשי עוצמת קול לדפדוף",
|
||||
"Show Page Navigation Buttons": "הצג כפתורי ניווט בעמוד",
|
||||
"Annotation Tools": "כלי הערות",
|
||||
"Enable Quick Actions": "הפעל פעולות מהירות",
|
||||
@@ -938,7 +937,6 @@
|
||||
"Maximum Number of Columns": "מספר עמודות מקסימלי",
|
||||
"Maximum Column Height": "גובה עמודה מקסימלי",
|
||||
"Maximum Column Width": "רוחב עמודה מקסימלי",
|
||||
"Apply also in Scrolled Mode": "החל גם במצב גלילה",
|
||||
"Header & Footer": "כותרת עליונה ותחתונה",
|
||||
"Show Header": "הצג כותרת עליונה",
|
||||
"Show Footer": "הצג כותרת תחתונה",
|
||||
@@ -1437,5 +1435,27 @@
|
||||
"Start your library": "התחילו את הספרייה שלכם",
|
||||
"Pick a book from your device to add it to your library.": "בחרו ספר מהמכשיר שלכם כדי להוסיף אותו לספרייה.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "שחררו ספר בכל מקום בחלון הזה, או בחרו אחד מהמחשב שלכם.",
|
||||
"Sign in to sync your library": "התחברו לסנכרון הספרייה שלכם"
|
||||
"Sign in to sync your library": "התחברו לסנכרון הספרייה שלכם",
|
||||
"Clear": "נקה",
|
||||
"Listening…": "מאזין…",
|
||||
"Set key": "הגדר מקש",
|
||||
"Page Turner": "מהפך עמודים",
|
||||
"Media Next": "מדיה הבא",
|
||||
"Media Previous": "מדיה הקודם",
|
||||
"Media Play/Pause": "מדיה ניגון/השהייה",
|
||||
"Media Fast Forward": "מדיה הרצה מהירה",
|
||||
"Media Rewind": "מדיה הרצה לאחור",
|
||||
"Volume Up": "הגבר עוצמה",
|
||||
"Volume Down": "הנמך עוצמה",
|
||||
"Arrow Left": "חץ שמאלה",
|
||||
"Arrow Right": "חץ ימינה",
|
||||
"Arrow Up": "חץ למעלה",
|
||||
"Arrow Down": "חץ למטה",
|
||||
"Page Up": "עמוד קודם",
|
||||
"Page Down": "עמוד הבא",
|
||||
"Space": "רווח",
|
||||
"Enter": "אנטר",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "לחץ על כפתור בשלט הרחוק או במקלדת לאחר הקשה על \"הגדר מקש\".",
|
||||
"Use Volume Keys": "השתמש במקשי עוצמת קול",
|
||||
"Custom Page Turner": "מהפך עמודים מותאם אישית"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "CJK फ़ॉन्ट",
|
||||
"Clear Search": "खोज साफ करें",
|
||||
"Header & Footer": "हेडर और फ़ुटर",
|
||||
"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?": "अब डाउनलोड और इंस्टॉल करें?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "ग्रिड",
|
||||
"(from 'As You Like It', Act II)": "('जैसा आप इसे पसंद करते हैं', अधिनियम II)",
|
||||
"Link Color": "लिंक रंग",
|
||||
"Volume Keys for Page Flip": "पृष्ठ फ़्लिप के लिए वॉल्यूम कुंजियाँ",
|
||||
"Screen": "स्क्रीन",
|
||||
"Orientation": "अवयव",
|
||||
"Portrait": "पोर्ट्रेट",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "अपनी लाइब्रेरी शुरू करें",
|
||||
"Pick a book from your device to add it to your library.": "अपनी लाइब्रेरी में जोड़ने के लिए अपने डिवाइस से एक किताब चुनें।",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "इस विंडो में कहीं भी एक किताब छोड़ें, या अपने कंप्यूटर से कोई एक चुनें।",
|
||||
"Sign in to sync your library": "अपनी लाइब्रेरी सिंक करने के लिए साइन इन करें"
|
||||
"Sign in to sync your library": "अपनी लाइब्रेरी सिंक करने के लिए साइन इन करें",
|
||||
"Clear": "साफ़ करें",
|
||||
"Listening…": "सुन रहे हैं…",
|
||||
"Set key": "कुंजी सेट करें",
|
||||
"Page Turner": "पेज टर्नर",
|
||||
"Media Next": "मीडिया अगला",
|
||||
"Media Previous": "मीडिया पिछला",
|
||||
"Media Play/Pause": "मीडिया प्ले/पॉज़",
|
||||
"Media Fast Forward": "मीडिया फ़ास्ट फ़ॉरवर्ड",
|
||||
"Media Rewind": "मीडिया रिवाइंड",
|
||||
"Volume Up": "वॉल्यूम बढ़ाएं",
|
||||
"Volume Down": "वॉल्यूम घटाएं",
|
||||
"Arrow Left": "बाएं तीर",
|
||||
"Arrow Right": "दाएं तीर",
|
||||
"Arrow Up": "ऊपर तीर",
|
||||
"Arrow Down": "नीचे तीर",
|
||||
"Page Up": "पेज ऊपर",
|
||||
"Page Down": "पेज नीचे",
|
||||
"Space": "स्पेस",
|
||||
"Enter": "एंटर",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"कुंजी सेट करें\" दबाने के बाद अपने रिमोट कंट्रोलर या कीबोर्ड पर एक बटन दबाएं।",
|
||||
"Use Volume Keys": "वॉल्यूम कुंजियों का उपयोग करें",
|
||||
"Custom Page Turner": "कस्टम पेज टर्नर"
|
||||
}
|
||||
|
||||
@@ -930,7 +930,6 @@
|
||||
"Swap Click Sides": "Kattintási oldalak cseréje",
|
||||
"Disable Double Tap": "Dupla koppintás letiltása",
|
||||
"Disable Double Click": "Dupla kattintás letiltása",
|
||||
"Volume Keys for Page Flip": "Hangerőgombok a lapozáshoz",
|
||||
"Show Page Navigation Buttons": "Oldalnavigációs gombok megjelenítése",
|
||||
"Annotation Tools": "Jegyzetelési eszközök",
|
||||
"Enable Quick Actions": "Gyorsműveletek engedélyezése",
|
||||
@@ -1018,7 +1017,6 @@
|
||||
"Maximum Number of Columns": "Oszlopok maximális száma",
|
||||
"Maximum Column Height": "Maximális oszlopmagasság",
|
||||
"Maximum Column Width": "Maximális oszlopszélesség",
|
||||
"Apply also in Scrolled Mode": "Alkalmazás görgetett módban is",
|
||||
"Header & Footer": "Fejléc és lábléc",
|
||||
"Show Header": "Fejléc megjelenítése",
|
||||
"Show Footer": "Lábléc megjelenítése",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "Indítsa el a könyvtárát",
|
||||
"Pick a book from your device to add it to your library.": "Válasszon egy könyvet az eszközéről, hogy hozzáadja a könyvtárához.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Húzzon egy könyvet bárhová ezen az ablakon, vagy válasszon egyet a számítógépéről.",
|
||||
"Sign in to sync your library": "Jelentkezzen be a könyvtár szinkronizálásához"
|
||||
"Sign in to sync your library": "Jelentkezzen be a könyvtár szinkronizálásához",
|
||||
"Clear": "Törlés",
|
||||
"Listening…": "Figyelés…",
|
||||
"Set key": "Billentyű beállítása",
|
||||
"Page Turner": "Lapozó eszköz",
|
||||
"Media Next": "Média következő",
|
||||
"Media Previous": "Média előző",
|
||||
"Media Play/Pause": "Média lejátszás/szünet",
|
||||
"Media Fast Forward": "Média gyors előre",
|
||||
"Media Rewind": "Média visszatekerés",
|
||||
"Volume Up": "Hangerő növelése",
|
||||
"Volume Down": "Hangerő csökkentése",
|
||||
"Arrow Left": "Bal nyíl",
|
||||
"Arrow Right": "Jobb nyíl",
|
||||
"Arrow Up": "Fel nyíl",
|
||||
"Arrow Down": "Le nyíl",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Szóköz",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Nyomjon meg egy gombot a távirányítón vagy a billentyűzeten a „Billentyű beállítása” érintése után.",
|
||||
"Use Volume Keys": "Hangerőgombok használata",
|
||||
"Custom Page Turner": "Egyéni lapozó eszköz"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "Font CJK",
|
||||
"Clear Search": "Hapus Pencarian",
|
||||
"Header & Footer": "Header & Footer",
|
||||
"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?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Jala",
|
||||
"(from 'As You Like It', Act II)": "(dari 'Seperti yang Anda Inginkan', Bab II)",
|
||||
"Link Color": "Warna Tautan",
|
||||
"Volume Keys for Page Flip": "Volume Keys untuk Pembalikan Halaman",
|
||||
"Screen": "Screen",
|
||||
"Orientation": "Orientasi",
|
||||
"Portrait": "Potret",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "Mulai perpustakaan Anda",
|
||||
"Pick a book from your device to add it to your library.": "Pilih buku dari perangkat Anda untuk ditambahkan ke perpustakaan Anda.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Jatuhkan buku di mana saja pada jendela ini, atau pilih satu dari komputer Anda.",
|
||||
"Sign in to sync your library": "Masuk untuk menyinkronkan perpustakaan Anda"
|
||||
"Sign in to sync your library": "Masuk untuk menyinkronkan perpustakaan Anda",
|
||||
"Clear": "Hapus",
|
||||
"Listening…": "Mendengarkan…",
|
||||
"Set key": "Atur tombol",
|
||||
"Page Turner": "Pembalik Halaman",
|
||||
"Media Next": "Media Berikutnya",
|
||||
"Media Previous": "Media Sebelumnya",
|
||||
"Media Play/Pause": "Media Putar/Jeda",
|
||||
"Media Fast Forward": "Media Maju Cepat",
|
||||
"Media Rewind": "Media Mundur",
|
||||
"Volume Up": "Volume Naik",
|
||||
"Volume Down": "Volume Turun",
|
||||
"Arrow Left": "Panah Kiri",
|
||||
"Arrow Right": "Panah Kanan",
|
||||
"Arrow Up": "Panah Atas",
|
||||
"Arrow Down": "Panah Bawah",
|
||||
"Page Up": "Halaman Atas",
|
||||
"Page Down": "Halaman Bawah",
|
||||
"Space": "Spasi",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Tekan tombol pada remote controller atau keyboard Anda setelah mengetuk \"Atur tombol\".",
|
||||
"Use Volume Keys": "Gunakan Tombol Volume",
|
||||
"Custom Page Turner": "Pembalik Halaman Kustom"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"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",
|
||||
"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?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Griglia",
|
||||
"(from 'As You Like It', Act II)": "(da 'Come vi piace', Atto II)",
|
||||
"Link Color": "Colore link",
|
||||
"Volume Keys for Page Flip": "Tasti volume per girare pagina",
|
||||
"Screen": "Schermo",
|
||||
"Orientation": "Orientamento",
|
||||
"Portrait": "Ritratto",
|
||||
@@ -1437,5 +1435,27 @@
|
||||
"Start your library": "Inizia la tua biblioteca",
|
||||
"Pick a book from your device to add it to your library.": "Scegli un libro dal tuo dispositivo per aggiungerlo alla tua biblioteca.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Trascina un libro in qualsiasi punto di questa finestra, o sceglilo dal tuo computer.",
|
||||
"Sign in to sync your library": "Accedi per sincronizzare la tua biblioteca"
|
||||
"Sign in to sync your library": "Accedi per sincronizzare la tua biblioteca",
|
||||
"Clear": "Cancella",
|
||||
"Listening…": "In ascolto…",
|
||||
"Set key": "Imposta tasto",
|
||||
"Page Turner": "Giratore di pagine",
|
||||
"Media Next": "Multimediale: Successivo",
|
||||
"Media Previous": "Multimediale: Precedente",
|
||||
"Media Play/Pause": "Multimediale: Riproduci/Pausa",
|
||||
"Media Fast Forward": "Multimediale: Avanzamento rapido",
|
||||
"Media Rewind": "Multimediale: Riavvolgimento",
|
||||
"Volume Up": "Volume su",
|
||||
"Volume Down": "Volume giù",
|
||||
"Arrow Left": "Freccia sinistra",
|
||||
"Arrow Right": "Freccia destra",
|
||||
"Arrow Up": "Freccia su",
|
||||
"Arrow Down": "Freccia giù",
|
||||
"Page Up": "Pag su",
|
||||
"Page Down": "Pag giù",
|
||||
"Space": "Spazio",
|
||||
"Enter": "Invio",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Premi un pulsante sul telecomando o sulla tastiera dopo aver toccato \"Imposta tasto\".",
|
||||
"Use Volume Keys": "Usa i tasti del volume",
|
||||
"Custom Page Turner": "Giratore di pagine personalizzato"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "CJKフォント",
|
||||
"Clear Search": "検索をクリア",
|
||||
"Header & Footer": "ヘッダーとフッター",
|
||||
"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?": "今すぐダウンロードしてインストールしますか?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "グリッド",
|
||||
"(from 'As You Like It', Act II)": "(「お気に召すまま」第2幕)",
|
||||
"Link Color": "リンクカラー",
|
||||
"Volume Keys for Page Flip": "音量キーでページめくり",
|
||||
"Screen": "画面",
|
||||
"Orientation": "向き",
|
||||
"Portrait": "縦",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "ライブラリーを作成しましょう",
|
||||
"Pick a book from your device to add it to your library.": "デバイスから本を選んでライブラリーに追加しましょう。",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "このウィンドウの好きな場所に本をドロップするか、コンピューターから選んでください。",
|
||||
"Sign in to sync your library": "サインインしてライブラリーを同期"
|
||||
"Sign in to sync your library": "サインインしてライブラリーを同期",
|
||||
"Clear": "クリア",
|
||||
"Listening…": "待機中…",
|
||||
"Set key": "キーを設定",
|
||||
"Page Turner": "ページターナー",
|
||||
"Media Next": "メディア: 次へ",
|
||||
"Media Previous": "メディア: 前へ",
|
||||
"Media Play/Pause": "メディア: 再生/一時停止",
|
||||
"Media Fast Forward": "メディア: 早送り",
|
||||
"Media Rewind": "メディア: 巻き戻し",
|
||||
"Volume Up": "音量を上げる",
|
||||
"Volume Down": "音量を下げる",
|
||||
"Arrow Left": "左矢印",
|
||||
"Arrow Right": "右矢印",
|
||||
"Arrow Up": "上矢印",
|
||||
"Arrow Down": "下矢印",
|
||||
"Page Up": "ページアップ",
|
||||
"Page Down": "ページダウン",
|
||||
"Space": "スペース",
|
||||
"Enter": "エンター",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "「キーを設定」をタップした後、リモコンまたはキーボードのボタンを押してください。",
|
||||
"Use Volume Keys": "音量キーを使用",
|
||||
"Custom Page Turner": "カスタムページターナー"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "CJK 글꼴",
|
||||
"Clear Search": "검색 지우기",
|
||||
"Header & Footer": "헤더 및 푸터",
|
||||
"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?": "지금 다운로드하고 설치하시겠습니까?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "격자",
|
||||
"(from 'As You Like It', Act II)": "(당신이 좋아하는 대로, 2막)",
|
||||
"Link Color": "링크 색상",
|
||||
"Volume Keys for Page Flip": "페이지 넘김을 위한 볼륨 키",
|
||||
"Screen": "화면",
|
||||
"Orientation": "방향",
|
||||
"Portrait": "세로",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "서재 만들기",
|
||||
"Pick a book from your device to add it to your library.": "기기에서 책을 골라 서재에 추가하세요.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "이 창의 아무 곳에나 책을 놓거나, 컴퓨터에서 골라 보세요.",
|
||||
"Sign in to sync your library": "로그인하여 서재 동기화"
|
||||
"Sign in to sync your library": "로그인하여 서재 동기화",
|
||||
"Clear": "지우기",
|
||||
"Listening…": "대기 중…",
|
||||
"Set key": "키 설정",
|
||||
"Page Turner": "페이지 터너",
|
||||
"Media Next": "미디어: 다음",
|
||||
"Media Previous": "미디어: 이전",
|
||||
"Media Play/Pause": "미디어: 재생/일시정지",
|
||||
"Media Fast Forward": "미디어: 빨리 감기",
|
||||
"Media Rewind": "미디어: 되감기",
|
||||
"Volume Up": "볼륨 높이기",
|
||||
"Volume Down": "볼륨 낮추기",
|
||||
"Arrow Left": "왼쪽 화살표",
|
||||
"Arrow Right": "오른쪽 화살표",
|
||||
"Arrow Up": "위쪽 화살표",
|
||||
"Arrow Down": "아래쪽 화살표",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "스페이스",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"키 설정\"을 탭한 후 리모컨 또는 키보드의 버튼을 누르세요.",
|
||||
"Use Volume Keys": "볼륨 키 사용",
|
||||
"Custom Page Turner": "사용자 지정 페이지 넘기기"
|
||||
}
|
||||
|
||||
@@ -502,7 +502,6 @@
|
||||
"Swap Click Sides": "Tukar Sisi Klik",
|
||||
"Disable Double Tap": "Lumpuhkan Ketuk Dua Kali",
|
||||
"Disable Double Click": "Lumpuhkan Klik Dua Kali",
|
||||
"Volume Keys for Page Flip": "Kekunci Volum untuk Balik Halaman",
|
||||
"Animation": "Animasi",
|
||||
"Paging Animation": "Animasi Halaman",
|
||||
"Device": "Peranti",
|
||||
@@ -584,7 +583,6 @@
|
||||
"Maximum Number of Columns": "Bilangan Maksimum Lajur",
|
||||
"Maximum Column Height": "Tinggi Maksimum Lajur",
|
||||
"Maximum Column Width": "Lebar Maksimum Lajur",
|
||||
"Apply also in Scrolled Mode": "Gunakan juga dalam Mod Tatal",
|
||||
"Header & Footer": "Pengepala & Pengaki",
|
||||
"Show Header": "Tunjuk Pengepala",
|
||||
"Show Footer": "Tunjuk Pengaki",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "Mulakan perpustakaan anda",
|
||||
"Pick a book from your device to add it to your library.": "Pilih buku dari peranti anda untuk ditambahkan ke perpustakaan anda.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Lepaskan buku di mana-mana pada tetingkap ini, atau pilih satu dari komputer anda.",
|
||||
"Sign in to sync your library": "Daftar masuk untuk menyegerakkan perpustakaan anda"
|
||||
"Sign in to sync your library": "Daftar masuk untuk menyegerakkan perpustakaan anda",
|
||||
"Clear": "Kosongkan",
|
||||
"Listening…": "Mendengar…",
|
||||
"Set key": "Tetapkan kekunci",
|
||||
"Page Turner": "Pembalik Halaman",
|
||||
"Media Next": "Media Seterusnya",
|
||||
"Media Previous": "Media Sebelumnya",
|
||||
"Media Play/Pause": "Media Main/Jeda",
|
||||
"Media Fast Forward": "Media Maju Laju",
|
||||
"Media Rewind": "Media Undur",
|
||||
"Volume Up": "Naikkan Kelantangan",
|
||||
"Volume Down": "Turunkan Kelantangan",
|
||||
"Arrow Left": "Anak Panah Kiri",
|
||||
"Arrow Right": "Anak Panah Kanan",
|
||||
"Arrow Up": "Anak Panah Atas",
|
||||
"Arrow Down": "Anak Panah Bawah",
|
||||
"Page Up": "Halaman Atas",
|
||||
"Page Down": "Halaman Bawah",
|
||||
"Space": "Ruang",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Tekan butang pada pengawal jauh atau papan kekunci anda selepas mengetuk \"Tetapkan kekunci\".",
|
||||
"Use Volume Keys": "Guna Kekunci Kelantangan",
|
||||
"Custom Page Turner": "Pembalik Halaman Tersuai"
|
||||
}
|
||||
|
||||
@@ -168,7 +168,6 @@
|
||||
"Header & Footer": "Koptekst & voettekst",
|
||||
"Show Header": "Koptekst weergeven",
|
||||
"Show Footer": "Voettekst weergeven",
|
||||
"Apply also in Scrolled Mode": "Ook toepassen in scroll-modus",
|
||||
"Auto": "Automatisch",
|
||||
"Language": "Taal",
|
||||
"Animation": "Animatie",
|
||||
@@ -178,7 +177,6 @@
|
||||
"Portrait": "Portret",
|
||||
"Landscape": "Landschap",
|
||||
"Behavior": "Gedrag",
|
||||
"Volume Keys for Page Flip": "Volumetoetsen voor pagina omslaan",
|
||||
"Apply": "Toepassen",
|
||||
"Font": "Lettertype",
|
||||
"Layout": "Opmaak",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "Begin je bibliotheek",
|
||||
"Pick a book from your device to add it to your library.": "Kies een boek van je apparaat om aan je bibliotheek toe te voegen.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Sleep een boek ergens in dit venster, of kies er een van je computer.",
|
||||
"Sign in to sync your library": "Meld je aan om je bibliotheek te synchroniseren"
|
||||
"Sign in to sync your library": "Meld je aan om je bibliotheek te synchroniseren",
|
||||
"Clear": "Wissen",
|
||||
"Listening…": "Luisteren…",
|
||||
"Set key": "Toets instellen",
|
||||
"Page Turner": "Pagina-omslaan",
|
||||
"Media Next": "Media: Volgende",
|
||||
"Media Previous": "Media: Vorige",
|
||||
"Media Play/Pause": "Media: Afspelen/Pauzeren",
|
||||
"Media Fast Forward": "Media: Snel vooruitspoelen",
|
||||
"Media Rewind": "Media: Terugspoelen",
|
||||
"Volume Up": "Volume omhoog",
|
||||
"Volume Down": "Volume omlaag",
|
||||
"Arrow Left": "Pijl links",
|
||||
"Arrow Right": "Pijl rechts",
|
||||
"Arrow Up": "Pijl omhoog",
|
||||
"Arrow Down": "Pijl omlaag",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Spatie",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Druk op een knop op uw afstandsbediening of toetsenbord nadat u op \"Toets instellen\" hebt getikt.",
|
||||
"Use Volume Keys": "Volumetoetsen gebruiken",
|
||||
"Custom Page Turner": "Aangepaste paginaknop"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"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",
|
||||
"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?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Siatka",
|
||||
"(from 'As You Like It', Act II)": "(z „Jak wam się podoba”, Akt II)",
|
||||
"Link Color": "Kolor linku",
|
||||
"Volume Keys for Page Flip": "Klucze głośności do przewracania stron",
|
||||
"Screen": "Ekran",
|
||||
"Orientation": "Orientacja",
|
||||
"Portrait": "Portret",
|
||||
@@ -1462,5 +1460,27 @@
|
||||
"Start your library": "Rozpocznij swoją bibliotekę",
|
||||
"Pick a book from your device to add it to your library.": "Wybierz książkę z urządzenia, aby dodać ją do swojej biblioteki.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Upuść książkę w dowolnym miejscu tego okna lub wybierz ją z komputera.",
|
||||
"Sign in to sync your library": "Zaloguj się, aby zsynchronizować bibliotekę"
|
||||
"Sign in to sync your library": "Zaloguj się, aby zsynchronizować bibliotekę",
|
||||
"Clear": "Wyczyść",
|
||||
"Listening…": "Nasłuchiwanie…",
|
||||
"Set key": "Ustaw klawisz",
|
||||
"Page Turner": "Przewijacz stron",
|
||||
"Media Next": "Media: Następny",
|
||||
"Media Previous": "Media: Poprzedni",
|
||||
"Media Play/Pause": "Media: Odtwórz/Pauza",
|
||||
"Media Fast Forward": "Media: Przewiń do przodu",
|
||||
"Media Rewind": "Media: Przewiń do tyłu",
|
||||
"Volume Up": "Głośność+",
|
||||
"Volume Down": "Głośność−",
|
||||
"Arrow Left": "Strzałka w lewo",
|
||||
"Arrow Right": "Strzałka w prawo",
|
||||
"Arrow Up": "Strzałka w górę",
|
||||
"Arrow Down": "Strzałka w dół",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Spacja",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Naciśnij przycisk na pilocie lub klawiaturze po dotknięciu \"Ustaw klawisz\".",
|
||||
"Use Volume Keys": "Używaj klawiszy głośności",
|
||||
"Custom Page Turner": "Własne przełączanie stron"
|
||||
}
|
||||
|
||||
@@ -1046,7 +1046,6 @@
|
||||
"Swap Click Sides": "Trocar lados do clique",
|
||||
"Disable Double Tap": "Desativar toque duplo",
|
||||
"Disable Double Click": "Desativar clique duplo",
|
||||
"Volume Keys for Page Flip": "Teclas de volume para virar página",
|
||||
"Show Page Navigation Buttons": "Botões de navegação",
|
||||
"Annotation Tools": "Ferramentas de anotação",
|
||||
"Enable Quick Actions": "Ativar ações rápidas",
|
||||
@@ -1167,7 +1166,6 @@
|
||||
"Maximum Number of Columns": "Número máximo de colunas",
|
||||
"Maximum Column Height": "Altura máxima da coluna",
|
||||
"Maximum Column Width": "Largura máxima da coluna",
|
||||
"Apply also in Scrolled Mode": "Aplicar também no modo de rolagem",
|
||||
"Header & Footer": "Cabeçalho e rodapé",
|
||||
"Show Header": "Mostrar cabeçalho",
|
||||
"Show Footer": "Mostrar rodapé",
|
||||
@@ -1437,5 +1435,27 @@
|
||||
"Start your library": "Comece sua biblioteca",
|
||||
"Pick a book from your device to add it to your library.": "Escolha um livro do seu dispositivo para adicionar à sua biblioteca.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Solte um livro em qualquer parte desta janela, ou escolha um do seu computador.",
|
||||
"Sign in to sync your library": "Entre para sincronizar sua biblioteca"
|
||||
"Sign in to sync your library": "Entre para sincronizar sua biblioteca",
|
||||
"Clear": "Limpar",
|
||||
"Listening…": "Aguardando…",
|
||||
"Set key": "Definir tecla",
|
||||
"Page Turner": "Virador de páginas",
|
||||
"Media Next": "Mídia: Próxima",
|
||||
"Media Previous": "Mídia: Anterior",
|
||||
"Media Play/Pause": "Mídia: Reproduzir/Pausar",
|
||||
"Media Fast Forward": "Mídia: Avançar",
|
||||
"Media Rewind": "Mídia: Retroceder",
|
||||
"Volume Up": "Volume para cima",
|
||||
"Volume Down": "Volume para baixo",
|
||||
"Arrow Left": "Seta para esquerda",
|
||||
"Arrow Right": "Seta para direita",
|
||||
"Arrow Up": "Seta para cima",
|
||||
"Arrow Down": "Seta para baixo",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Espaço",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Pressione um botão no controle remoto ou teclado após tocar em \"Definir tecla\".",
|
||||
"Use Volume Keys": "Usar teclas de volume",
|
||||
"Custom Page Turner": "Virador de páginas personalizado"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"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",
|
||||
"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?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Grade",
|
||||
"(from 'As You Like It', Act II)": "(de 'Como Gostais', Ato II)",
|
||||
"Link Color": "Cor do Link",
|
||||
"Volume Keys for Page Flip": "Teclas de Volume para Virar Página",
|
||||
"Screen": "Tela",
|
||||
"Orientation": "Orientação",
|
||||
"Portrait": "Retrato",
|
||||
@@ -1437,5 +1435,27 @@
|
||||
"Start your library": "Comece a sua biblioteca",
|
||||
"Pick a book from your device to add it to your library.": "Escolha um livro do seu dispositivo para adicionar à sua biblioteca.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Largue um livro em qualquer parte desta janela, ou escolha um do seu computador.",
|
||||
"Sign in to sync your library": "Inicie sessão para sincronizar a sua biblioteca"
|
||||
"Sign in to sync your library": "Inicie sessão para sincronizar a sua biblioteca",
|
||||
"Clear": "Limpar",
|
||||
"Listening…": "A aguardar…",
|
||||
"Set key": "Definir tecla",
|
||||
"Page Turner": "Virador de páginas",
|
||||
"Media Next": "Multimédia: Seguinte",
|
||||
"Media Previous": "Multimédia: Anterior",
|
||||
"Media Play/Pause": "Multimédia: Reproduzir/Pausar",
|
||||
"Media Fast Forward": "Multimédia: Avançar rapidamente",
|
||||
"Media Rewind": "Multimédia: Retroceder",
|
||||
"Volume Up": "Volume+",
|
||||
"Volume Down": "Volume−",
|
||||
"Arrow Left": "Seta esquerda",
|
||||
"Arrow Right": "Seta direita",
|
||||
"Arrow Up": "Seta cima",
|
||||
"Arrow Down": "Seta baixo",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Espaço",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Pressione um botão no seu controle remoto ou teclado após tocar em \"Definir tecla\".",
|
||||
"Use Volume Keys": "Usar teclas de volume",
|
||||
"Custom Page Turner": "Virador de página personalizado"
|
||||
}
|
||||
|
||||
@@ -918,7 +918,6 @@
|
||||
"Swap Click Sides": "Schimbă părțile de clic",
|
||||
"Disable Double Tap": "Dezactivează dubla apăsare",
|
||||
"Disable Double Click": "Dezactivează dublu clic",
|
||||
"Volume Keys for Page Flip": "Taste de volum pentru schimbarea paginii",
|
||||
"Show Page Navigation Buttons": "Afișează butoanele de navigare pe pagină",
|
||||
"Annotation Tools": "Instrumente de adnotare",
|
||||
"Enable Quick Actions": "Activează acțiunile rapide",
|
||||
@@ -1006,7 +1005,6 @@
|
||||
"Maximum Number of Columns": "Număr maxim de coloane",
|
||||
"Maximum Column Height": "Înălțimea maximă a coloanei",
|
||||
"Maximum Column Width": "Lățimea maximă a coloanei",
|
||||
"Apply also in Scrolled Mode": "Aplică și în modul Derulare",
|
||||
"Header & Footer": "Antet și Subsol",
|
||||
"Show Header": "Afișează antetul",
|
||||
"Show Footer": "Afișează subsolul",
|
||||
@@ -1437,5 +1435,27 @@
|
||||
"Start your library": "Începe-ți biblioteca",
|
||||
"Pick a book from your device to add it to your library.": "Alege o carte de pe dispozitiv pentru a o adăuga în biblioteca ta.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Lasă o carte oriunde în această fereastră sau alege una de pe computer.",
|
||||
"Sign in to sync your library": "Conectează-te pentru a-ți sincroniza biblioteca"
|
||||
"Sign in to sync your library": "Conectează-te pentru a-ți sincroniza biblioteca",
|
||||
"Clear": "Șterge",
|
||||
"Listening…": "Ascultă…",
|
||||
"Set key": "Setează tasta",
|
||||
"Page Turner": "Dispozitiv de întoarcere pagini",
|
||||
"Media Next": "Media Următor",
|
||||
"Media Previous": "Media Anterior",
|
||||
"Media Play/Pause": "Media Redare/Pauză",
|
||||
"Media Fast Forward": "Media Derulare înainte",
|
||||
"Media Rewind": "Media Derulare înapoi",
|
||||
"Volume Up": "Volum mai mare",
|
||||
"Volume Down": "Volum mai mic",
|
||||
"Arrow Left": "Săgeată stânga",
|
||||
"Arrow Right": "Săgeată dreapta",
|
||||
"Arrow Up": "Săgeată sus",
|
||||
"Arrow Down": "Săgeată jos",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Spațiu",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Apăsați un buton pe telecomandă sau tastatură după ce atingeți \"Setează tasta\".",
|
||||
"Use Volume Keys": "Folosiți tastele de volum",
|
||||
"Custom Page Turner": "Dispozitiv personalizat de întoarcere pagini"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "CJK Шрифт",
|
||||
"Clear Search": "Очистить поиск",
|
||||
"Header & Footer": "Заголовок и нижний колонтитул",
|
||||
"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?": "Скачать и установить сейчас?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Сетка",
|
||||
"(from 'As You Like It', Act II)": "(из 'Как вам это понравится', Акт II)",
|
||||
"Link Color": "Цвет ссылки",
|
||||
"Volume Keys for Page Flip": "Клавиши громкости для перелистывания страниц",
|
||||
"Screen": "Экран",
|
||||
"Orientation": "Ориентация",
|
||||
"Portrait": "Портрет",
|
||||
@@ -1462,5 +1460,27 @@
|
||||
"Start your library": "Создайте свою библиотеку",
|
||||
"Pick a book from your device to add it to your library.": "Выберите книгу с устройства, чтобы добавить её в библиотеку.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Перетащите книгу в любое место этого окна или выберите её на компьютере.",
|
||||
"Sign in to sync your library": "Войдите, чтобы синхронизировать библиотеку"
|
||||
"Sign in to sync your library": "Войдите, чтобы синхронизировать библиотеку",
|
||||
"Clear": "Очистить",
|
||||
"Listening…": "Ожидание…",
|
||||
"Set key": "Назначить клавишу",
|
||||
"Page Turner": "Листалка страниц",
|
||||
"Media Next": "Медиа: Следующий",
|
||||
"Media Previous": "Медиа: Предыдущий",
|
||||
"Media Play/Pause": "Медиа: Воспроизведение/Пауза",
|
||||
"Media Fast Forward": "Медиа: Перемотка вперёд",
|
||||
"Media Rewind": "Медиа: Перемотка назад",
|
||||
"Volume Up": "Громкость+",
|
||||
"Volume Down": "Громкость−",
|
||||
"Arrow Left": "Стрелка влево",
|
||||
"Arrow Right": "Стрелка вправо",
|
||||
"Arrow Up": "Стрелка вверх",
|
||||
"Arrow Down": "Стрелка вниз",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Пробел",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Нажмите кнопку на пульте дистанционного управления или клавиатуре после нажатия \"Назначить клавишу\".",
|
||||
"Use Volume Keys": "Использовать клавиши громкости",
|
||||
"Custom Page Turner": "Пользовательское перелистывание страниц"
|
||||
}
|
||||
|
||||
@@ -195,7 +195,6 @@
|
||||
"Scrolled Mode": "අනුචලන ආකාරය",
|
||||
"Overlap Pixels": "අතිච්ඡාදන පික්සල්",
|
||||
"Disable Double Click": "ද්විත්ව ක්ලික් අබල කරන්න",
|
||||
"Volume Keys for Page Flip": "පිටු පෙරැළීම සඳහා ශබ්ද යතුර",
|
||||
"Animation": "සජීවිකරණය",
|
||||
"Paging Animation": "පිටු සජීවිකරණය",
|
||||
"Security": "ආරක්ෂාව",
|
||||
@@ -269,7 +268,6 @@
|
||||
"Reading Progress Style": "කියවීමේ ප්රගති ශෛලිය",
|
||||
"Page Number": "පිටු අංකය",
|
||||
"Percentage": "ප්රතිශතය",
|
||||
"Apply also in Scrolled Mode": "අනුචලන ආකාරයේදීද අනුගත කරන්න",
|
||||
"Screen": "තිරය",
|
||||
"Orientation": "දිශානතිය",
|
||||
"Portrait": "සිරස්",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "ඔබේ පුස්තකාලය ආරම්භ කරන්න",
|
||||
"Pick a book from your device to add it to your library.": "ඔබේ පුස්තකාලයට එක් කිරීමට ඔබේ උපාංගයෙන් පොතක් තෝරන්න.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "මෙම කවුළුවේ ඕනෑම තැනක පොතක් දමන්න, නැතහොත් ඔබේ පරිගණකයෙන් එකක් තෝරන්න.",
|
||||
"Sign in to sync your library": "ඔබේ පුස්තකාලය සමමුහුර්ත කිරීමට පුරනය වන්න"
|
||||
"Sign in to sync your library": "ඔබේ පුස්තකාලය සමමුහුර්ත කිරීමට පුරනය වන්න",
|
||||
"Clear": "හිස් කරන්න",
|
||||
"Listening…": "සවන් දෙමින්…",
|
||||
"Set key": "යතුර සකසන්න",
|
||||
"Page Turner": "පිටු හරවනය",
|
||||
"Media Next": "මාධ්ය ඊළඟ",
|
||||
"Media Previous": "මාධ්ය පෙර",
|
||||
"Media Play/Pause": "මාධ්ය ධාවනය/විරාමය",
|
||||
"Media Fast Forward": "මාධ්ය වේගයෙන් ඉදිරියට",
|
||||
"Media Rewind": "මාධ්ය ආපසු",
|
||||
"Volume Up": "ශබ්දය වැඩි කරන්න",
|
||||
"Volume Down": "ශබ්දය අඩු කරන්න",
|
||||
"Arrow Left": "වම් ඊතලය",
|
||||
"Arrow Right": "දකුණු ඊතලය",
|
||||
"Arrow Up": "ඉහළ ඊතලය",
|
||||
"Arrow Down": "පහළ ඊතලය",
|
||||
"Page Up": "පිටුව ඉහළට",
|
||||
"Page Down": "පිටුව පහළට",
|
||||
"Space": "අවකාශය",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"යතුර සකසන්න\" තට්ටු කිරීමෙන් පසු ඔබේ දුරස්ථ පාලකයේ හෝ යතුරු පුවරුවේ බොත්තමක් එබෙන්න.",
|
||||
"Use Volume Keys": "ශබ්ද කතා යතුරු භාවිතා කරන්න",
|
||||
"Custom Page Turner": "අභිරුචි පිටු හරවනය"
|
||||
}
|
||||
|
||||
@@ -889,7 +889,6 @@
|
||||
"Swap Click Sides": "Zamenjaj strani za klike",
|
||||
"Disable Double Tap": "Onemogoči dvojni tap",
|
||||
"Disable Double Click": "Onemogoči dvojni klik",
|
||||
"Volume Keys for Page Flip": "Tipke za glasnost za obračanje strani",
|
||||
"Show Page Navigation Buttons": "Prikaži gumbe za navigacijo po straneh",
|
||||
"Annotation Tools": "Orodja za opombe",
|
||||
"Enable Quick Actions": "Omogoči hitra dejanja",
|
||||
@@ -978,7 +977,6 @@
|
||||
"Maximum Number of Columns": "Največje število stolpcev",
|
||||
"Maximum Column Height": "Največja višina stolpca",
|
||||
"Maximum Column Width": "Največja širina stolpca",
|
||||
"Apply also in Scrolled Mode": "Uporabi tudi v načinu pomikanja",
|
||||
"Header & Footer": "Glava in noga",
|
||||
"Show Header": "Prikaži glavo",
|
||||
"Show Footer": "Prikaži nogo",
|
||||
@@ -1462,5 +1460,27 @@
|
||||
"Start your library": "Začnite svojo knjižnico",
|
||||
"Pick a book from your device to add it to your library.": "Izberite knjigo iz svoje naprave, da jo dodate v svojo knjižnico.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Spustite knjigo kjer koli v tem oknu ali jo izberite iz svojega računalnika.",
|
||||
"Sign in to sync your library": "Prijavite se za sinhronizacijo svoje knjižnice"
|
||||
"Sign in to sync your library": "Prijavite se za sinhronizacijo svoje knjižnice",
|
||||
"Clear": "Počisti",
|
||||
"Listening…": "Poslušanje…",
|
||||
"Set key": "Nastavi tipko",
|
||||
"Page Turner": "Obračalnik strani",
|
||||
"Media Next": "Mediji: Naslednje",
|
||||
"Media Previous": "Mediji: Prejšnje",
|
||||
"Media Play/Pause": "Mediji: Predvajaj/Premor",
|
||||
"Media Fast Forward": "Mediji: Hitro naprej",
|
||||
"Media Rewind": "Mediji: Previj nazaj",
|
||||
"Volume Up": "Glasnost+",
|
||||
"Volume Down": "Glasnost−",
|
||||
"Arrow Left": "Puščica levo",
|
||||
"Arrow Right": "Puščica desno",
|
||||
"Arrow Up": "Puščica gor",
|
||||
"Arrow Down": "Puščica dol",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Preslednica",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Pritisnite gumb na daljinskem upravljalniku ali tipkovnici po tapkanju na \"Nastavi tipko\".",
|
||||
"Use Volume Keys": "Uporabi tipki za glasnost",
|
||||
"Custom Page Turner": "Tipka za obračanje strani po meri"
|
||||
}
|
||||
|
||||
@@ -441,7 +441,6 @@
|
||||
"Scroll": "Rullning",
|
||||
"Overlap Pixels": "Överlappande pixlar",
|
||||
"Disable Double Click": "Inaktivera dubbelklick",
|
||||
"Volume Keys for Page Flip": "Volymknappar för sidbyte",
|
||||
"Animation": "Animation",
|
||||
"Paging Animation": "Sidanimation",
|
||||
"Security": "Säkerhet",
|
||||
@@ -511,7 +510,6 @@
|
||||
"Reading Progress Style": "Läsframstegsstil",
|
||||
"Page Number": "Sidnummer",
|
||||
"Percentage": "Procent",
|
||||
"Apply also in Scrolled Mode": "Tillämpa även i rullningsläge",
|
||||
"Screen": "Skärm",
|
||||
"Orientation": "Orientering",
|
||||
"Portrait": "Porträtt",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "Starta ditt bibliotek",
|
||||
"Pick a book from your device to add it to your library.": "Välj en bok från din enhet att lägga till i ditt bibliotek.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Släpp en bok var som helst på det här fönstret, eller välj en från din dator.",
|
||||
"Sign in to sync your library": "Logga in för att synkronisera ditt bibliotek"
|
||||
"Sign in to sync your library": "Logga in för att synkronisera ditt bibliotek",
|
||||
"Clear": "Rensa",
|
||||
"Listening…": "Lyssnar…",
|
||||
"Set key": "Ange tangent",
|
||||
"Page Turner": "Sidvändare",
|
||||
"Media Next": "Media: Nästa",
|
||||
"Media Previous": "Media: Föregående",
|
||||
"Media Play/Pause": "Media: Spela/Pausa",
|
||||
"Media Fast Forward": "Media: Snabbspolning framåt",
|
||||
"Media Rewind": "Media: Snabbspolning bakåt",
|
||||
"Volume Up": "Volym upp",
|
||||
"Volume Down": "Volym ned",
|
||||
"Arrow Left": "Pil vänster",
|
||||
"Arrow Right": "Pil höger",
|
||||
"Arrow Up": "Pil upp",
|
||||
"Arrow Down": "Pil ned",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Mellanslag",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Tryck på en knapp på din fjärrkontroll eller tangentbord efter att ha tryckt på \"Ange tangent\".",
|
||||
"Use Volume Keys": "Använd volymknappar",
|
||||
"Custom Page Turner": "Anpassad sidvändare"
|
||||
}
|
||||
|
||||
@@ -195,7 +195,6 @@
|
||||
"Scrolled Mode": "உருட்டல் பயன்முறை",
|
||||
"Overlap Pixels": "ஒன்றுடன் ஒன்று பிக்சல்கள்",
|
||||
"Disable Double Click": "இரட்டை கிளிக்கை முடக்கவும்",
|
||||
"Volume Keys for Page Flip": "பக்கம் புரட்டுவதற்கு ஒலி விசைகள்",
|
||||
"Animation": "அனிமேஷன்",
|
||||
"Paging Animation": "பக்க அனிமேஷன்",
|
||||
"Security": "பாதுகாப்பு",
|
||||
@@ -269,7 +268,6 @@
|
||||
"Reading Progress Style": "வாசிப்பு முன்னேற்ற பாணி",
|
||||
"Page Number": "பக்க எண்",
|
||||
"Percentage": "சதவீதம்",
|
||||
"Apply also in Scrolled Mode": "உருட்டல் பயன்முறையிலும் பொருந்தும்",
|
||||
"Screen": "திரை",
|
||||
"Orientation": "திசைநிலை",
|
||||
"Portrait": "நிலைமான்",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "உங்கள் நூலகத்தைத் தொடங்குங்கள்",
|
||||
"Pick a book from your device to add it to your library.": "உங்கள் நூலகத்தில் சேர்க்க உங்கள் சாதனத்திலிருந்து ஒரு புத்தகத்தைத் தேர்ந்தெடுக்கவும்.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "இந்த சாளரத்தில் எங்கேனும் ஒரு புத்தகத்தை விடவும், அல்லது உங்கள் கணினியிலிருந்து ஒன்றைத் தேர்ந்தெடுக்கவும்.",
|
||||
"Sign in to sync your library": "உங்கள் நூலகத்தை ஒத்திசைக்க உள்நுழையவும்"
|
||||
"Sign in to sync your library": "உங்கள் நூலகத்தை ஒத்திசைக்க உள்நுழையவும்",
|
||||
"Clear": "அழி",
|
||||
"Listening…": "கேட்கிறது…",
|
||||
"Set key": "விசை அமை",
|
||||
"Page Turner": "பக்க திருப்பி",
|
||||
"Media Next": "மீடியா அடுத்தது",
|
||||
"Media Previous": "மீடியா முந்தையது",
|
||||
"Media Play/Pause": "மீடியா இயக்கு/இடைநிறுத்து",
|
||||
"Media Fast Forward": "மீடியா வேகமாக முன்னேறு",
|
||||
"Media Rewind": "மீடியா பின்னோக்கி",
|
||||
"Volume Up": "ஒலி அளவு அதிகரி",
|
||||
"Volume Down": "ஒலி அளவு குறை",
|
||||
"Arrow Left": "இடது அம்பு",
|
||||
"Arrow Right": "வலது அம்பு",
|
||||
"Arrow Up": "மேல் அம்பு",
|
||||
"Arrow Down": "கீழ் அம்பு",
|
||||
"Page Up": "பக்கம் மேலே",
|
||||
"Page Down": "பக்கம் கீழே",
|
||||
"Space": "இடைவெளி",
|
||||
"Enter": "என்டர்",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"விசை அமை\" தட்டிய பிறகு உங்கள் ரிமோட் கன்ட்ரோலர் அல்லது கீபோர்டில் ஒரு பட்டனை அழுத்தவும்.",
|
||||
"Use Volume Keys": "ஒலி அளவு விசைகளைப் பயன்படுத்து",
|
||||
"Custom Page Turner": "தனிப்பயன் பக்க திருப்பி"
|
||||
}
|
||||
|
||||
@@ -164,7 +164,6 @@
|
||||
"Scroll": "เลื่อน",
|
||||
"Scrolled Mode": "โหมดเลื่อน",
|
||||
"Overlap Pixels": "พิกเซลซ้อน",
|
||||
"Volume Keys for Page Flip": "ปุ่มเสียงเพื่อพลิกหน้า",
|
||||
"Animation": "ภาพเคลื่อนไหว",
|
||||
"Paging Animation": "ภาพเคลื่อนไหวพลิกหน้า",
|
||||
"Security": "ความปลอดภัย",
|
||||
@@ -227,7 +226,6 @@
|
||||
"Show Footer": "แสดงท้ายกระดาษ",
|
||||
"Show Remaining Time": "แสดงเวลาที่เหลือ",
|
||||
"Show Remaining Pages": "แสดงหน้าที่เหลือ",
|
||||
"Apply also in Scrolled Mode": "ใช้ในโหมดเลื่อนด้วย",
|
||||
"Screen": "หน้าจอ",
|
||||
"Orientation": "การวางแนว",
|
||||
"Portrait": "แนวตั้ง",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "เริ่มต้นห้องสมุดของคุณ",
|
||||
"Pick a book from your device to add it to your library.": "เลือกหนังสือจากอุปกรณ์ของคุณเพื่อเพิ่มลงในห้องสมุดของคุณ",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "วางหนังสือที่ใดก็ได้บนหน้าต่างนี้ หรือเลือกจากคอมพิวเตอร์ของคุณ",
|
||||
"Sign in to sync your library": "ลงชื่อเข้าใช้เพื่อซิงค์ห้องสมุดของคุณ"
|
||||
"Sign in to sync your library": "ลงชื่อเข้าใช้เพื่อซิงค์ห้องสมุดของคุณ",
|
||||
"Clear": "ล้าง",
|
||||
"Listening…": "กำลังฟัง…",
|
||||
"Set key": "ตั้งปุ่ม",
|
||||
"Page Turner": "ตัวพลิกหน้า",
|
||||
"Media Next": "มีเดียถัดไป",
|
||||
"Media Previous": "มีเดียก่อนหน้า",
|
||||
"Media Play/Pause": "มีเดียเล่น/หยุดชั่วคราว",
|
||||
"Media Fast Forward": "มีเดียเดินหน้าเร็ว",
|
||||
"Media Rewind": "มีเดียย้อนกลับ",
|
||||
"Volume Up": "เพิ่มระดับเสียง",
|
||||
"Volume Down": "ลดระดับเสียง",
|
||||
"Arrow Left": "ลูกศรซ้าย",
|
||||
"Arrow Right": "ลูกศรขวา",
|
||||
"Arrow Up": "ลูกศรขึ้น",
|
||||
"Arrow Down": "ลูกศรลง",
|
||||
"Page Up": "หน้าขึ้น",
|
||||
"Page Down": "หน้าลง",
|
||||
"Space": "สเปซบาร์",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "กดปุ่มบนรีโมทคอนโทรลหรือคีย์บอร์ดหลังจากแตะ \"ตั้งปุ่ม\"",
|
||||
"Use Volume Keys": "ใช้ปุ่มระดับเสียง",
|
||||
"Custom Page Turner": "ปุ่มพลิกหน้าแบบกำหนดเอง"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"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",
|
||||
"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?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Izgara",
|
||||
"(from 'As You Like It', Act II)": "(As You Like It, 2. Perde)",
|
||||
"Link Color": "Bağlantı Rengi",
|
||||
"Volume Keys for Page Flip": "Sayfa Çevirme için Ses Seviyesi Tuşları",
|
||||
"Screen": "Ekran",
|
||||
"Orientation": "Yönlendirme",
|
||||
"Portrait": "Portre",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "Kütüphanenizi başlatın",
|
||||
"Pick a book from your device to add it to your library.": "Kütüphanenize eklemek için cihazınızdan bir kitap seçin.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Bu pencerede herhangi bir yere bir kitap bırakın veya bilgisayarınızdan birini seçin.",
|
||||
"Sign in to sync your library": "Kütüphanenizi senkronize etmek için oturum açın"
|
||||
"Sign in to sync your library": "Kütüphanenizi senkronize etmek için oturum açın",
|
||||
"Clear": "Temizle",
|
||||
"Listening…": "Dinleniyor…",
|
||||
"Set key": "Tuş ayarla",
|
||||
"Page Turner": "Sayfa Çevirici",
|
||||
"Media Next": "Medya: Sonraki",
|
||||
"Media Previous": "Medya: Önceki",
|
||||
"Media Play/Pause": "Medya: Oynat/Duraklat",
|
||||
"Media Fast Forward": "Medya: Hızlı İleri",
|
||||
"Media Rewind": "Medya: Geri Sar",
|
||||
"Volume Up": "Ses Yükselt",
|
||||
"Volume Down": "Ses Kıs",
|
||||
"Arrow Left": "Sol Ok",
|
||||
"Arrow Right": "Sağ Ok",
|
||||
"Arrow Up": "Yukarı Ok",
|
||||
"Arrow Down": "Aşağı Ok",
|
||||
"Page Up": "Page Up",
|
||||
"Page Down": "Page Down",
|
||||
"Space": "Boşluk",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"Tuş ayarla\" düğmesine dokunduktan sonra uzaktan kumandanızdaki veya klavyenizdeki bir düğmeye basın.",
|
||||
"Use Volume Keys": "Ses Tuşlarını Kullan",
|
||||
"Custom Page Turner": "Özel Sayfa Çevirici"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "CJK шрифт",
|
||||
"Clear Search": "Очистити пошук",
|
||||
"Header & Footer": "Заголовок і нижній колонтитул",
|
||||
"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?": "Завантажити та встановити зараз?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Сітка",
|
||||
"(from 'As You Like It', Act II)": "(із 'Як вам це подобається', Дія II)",
|
||||
"Link Color": "Колір посилання",
|
||||
"Volume Keys for Page Flip": "Перегортати сторінки клавішами гучності",
|
||||
"Screen": "Екран",
|
||||
"Orientation": "Орієнтація",
|
||||
"Portrait": "Портрет",
|
||||
@@ -1462,5 +1460,27 @@
|
||||
"Start your library": "Створіть свою бібліотеку",
|
||||
"Pick a book from your device to add it to your library.": "Виберіть книжку з вашого пристрою, щоб додати її до бібліотеки.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Перетягніть книжку будь-куди у це вікно або виберіть її з комп’ютера.",
|
||||
"Sign in to sync your library": "Увійдіть, щоб синхронізувати бібліотеку"
|
||||
"Sign in to sync your library": "Увійдіть, щоб синхронізувати бібліотеку",
|
||||
"Clear": "Очистити",
|
||||
"Listening…": "Очікування…",
|
||||
"Set key": "Призначити клавішу",
|
||||
"Page Turner": "Перегортач сторінок",
|
||||
"Media Next": "Медіа: Наступний",
|
||||
"Media Previous": "Медіа: Попередній",
|
||||
"Media Play/Pause": "Медіа: Відтворення/Пауза",
|
||||
"Media Fast Forward": "Медіа: Перемотування вперед",
|
||||
"Media Rewind": "Медіа: Перемотування назад",
|
||||
"Volume Up": "Гучність+",
|
||||
"Volume Down": "Гучність−",
|
||||
"Arrow Left": "Стрілка ліворуч",
|
||||
"Arrow Right": "Стрілка праворуч",
|
||||
"Arrow Up": "Стрілка вгору",
|
||||
"Arrow Down": "Стрілка вниз",
|
||||
"Page Up": "Сторінка вгору",
|
||||
"Page Down": "Сторінка вниз",
|
||||
"Space": "Пробіл",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Натисніть кнопку на пульті або клавіатурі після натискання \"Призначити клавішу\".",
|
||||
"Use Volume Keys": "Використовувати клавіші гучності",
|
||||
"Custom Page Turner": "Власне перегортання сторінок"
|
||||
}
|
||||
|
||||
@@ -1026,7 +1026,6 @@
|
||||
"Swap Click Sides": "Bosish tomonlarini almashtirish",
|
||||
"Disable Double Tap": "Ikki marta bosishni oʻchirish",
|
||||
"Disable Double Click": "Ikki marta bosishni oʻchirish",
|
||||
"Volume Keys for Page Flip": "Sahifani aylantirish uchun ovoz tugmalari",
|
||||
"Show Page Navigation Buttons": "Sahifalararo navigatsiya tugmalarini koʻrsatish",
|
||||
"Annotation Tools": "Izoh vositalari",
|
||||
"Enable Quick Actions": "Tezkor amallarni yoqish",
|
||||
@@ -1146,7 +1145,6 @@
|
||||
"Maximum Number of Columns": "Maksimal ustunlar soni",
|
||||
"Maximum Column Height": "Maksimal ustun balandligi",
|
||||
"Maximum Column Width": "Maksimal ustun kengligi",
|
||||
"Apply also in Scrolled Mode": "Aylantirish rejimida ham qoʻllash",
|
||||
"Header & Footer": "Yuqori va pastki kolontitul",
|
||||
"Show Header": "Yuqori kolontitulni koʻrsatish",
|
||||
"Show Footer": "Pastki kolontitulni koʻrsatish",
|
||||
@@ -1412,5 +1410,27 @@
|
||||
"Start your library": "Kutubxonangizni boshlang",
|
||||
"Pick a book from your device to add it to your library.": "Kutubxonangizga qo‘shish uchun qurilmangizdan kitob tanlang.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Ushbu oynaning istalgan joyiga kitob tashlang yoki kompyuteringizdan birini tanlang.",
|
||||
"Sign in to sync your library": "Kutubxonangizni sinxronlash uchun tizimga kiring"
|
||||
"Sign in to sync your library": "Kutubxonangizni sinxronlash uchun tizimga kiring",
|
||||
"Clear": "Tozalash",
|
||||
"Listening…": "Tinglanmoqda…",
|
||||
"Set key": "Tugmani o'rnatish",
|
||||
"Page Turner": "Sahifa buruvchi",
|
||||
"Media Next": "Media keyingi",
|
||||
"Media Previous": "Media oldingi",
|
||||
"Media Play/Pause": "Media ijro/to'xtatish",
|
||||
"Media Fast Forward": "Media tez oldinga",
|
||||
"Media Rewind": "Media orqaga",
|
||||
"Volume Up": "Ovoz balandligi oshirish",
|
||||
"Volume Down": "Ovoz balandligi kamaytirish",
|
||||
"Arrow Left": "Chap o'q",
|
||||
"Arrow Right": "O'ng o'q",
|
||||
"Arrow Up": "Yuqori o'q",
|
||||
"Arrow Down": "Pastki o'q",
|
||||
"Page Up": "Sahifa yuqori",
|
||||
"Page Down": "Sahifa pastga",
|
||||
"Space": "Bo'sh joy",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "\"Tugmani o'rnatish\" tugmasini bosgandan so'ng masofadan boshqarish pultingiz yoki klaviaturangizdagi tugmani bosing.",
|
||||
"Use Volume Keys": "Ovoz balandligi tugmalarini ishlatish",
|
||||
"Custom Page Turner": "Maxsus sahifa buruvchi"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"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",
|
||||
"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ờ?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "Lưới",
|
||||
"(from 'As You Like It', Act II)": "(từ 'Như bạn thích', Hành động II)",
|
||||
"Link Color": "Màu liên kết",
|
||||
"Volume Keys for Page Flip": "Phím âm lượng để lật trang",
|
||||
"Screen": "Màn hình",
|
||||
"Orientation": "Định hướng",
|
||||
"Portrait": "Chân dung",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "Bắt đầu thư viện của bạn",
|
||||
"Pick a book from your device to add it to your library.": "Chọn một cuốn sách từ thiết bị để thêm vào thư viện của bạn.",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "Thả một cuốn sách vào bất kỳ đâu trên cửa sổ này, hoặc chọn một cuốn từ máy tính của bạn.",
|
||||
"Sign in to sync your library": "Đăng nhập để đồng bộ thư viện của bạn"
|
||||
"Sign in to sync your library": "Đăng nhập để đồng bộ thư viện của bạn",
|
||||
"Clear": "Xóa",
|
||||
"Listening…": "Đang lắng nghe…",
|
||||
"Set key": "Đặt phím",
|
||||
"Page Turner": "Bộ Lật Trang",
|
||||
"Media Next": "Media Tiếp Theo",
|
||||
"Media Previous": "Media Trước",
|
||||
"Media Play/Pause": "Media Phát/Tạm Dừng",
|
||||
"Media Fast Forward": "Media Tua Nhanh",
|
||||
"Media Rewind": "Media Tua Lại",
|
||||
"Volume Up": "Tăng Âm Lượng",
|
||||
"Volume Down": "Giảm Âm Lượng",
|
||||
"Arrow Left": "Mũi Tên Trái",
|
||||
"Arrow Right": "Mũi Tên Phải",
|
||||
"Arrow Up": "Mũi Tên Lên",
|
||||
"Arrow Down": "Mũi Tên Xuống",
|
||||
"Page Up": "Trang Trên",
|
||||
"Page Down": "Trang Dưới",
|
||||
"Space": "Dấu Cách",
|
||||
"Enter": "Enter",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "Nhấn một nút trên bộ điều khiển từ xa hoặc bàn phím sau khi chạm \"Đặt phím\".",
|
||||
"Use Volume Keys": "Dùng Phím Âm Lượng",
|
||||
"Custom Page Turner": "Nút Lật Trang Tùy Chỉnh"
|
||||
}
|
||||
|
||||
@@ -229,7 +229,6 @@
|
||||
"CJK Font": "中文字体",
|
||||
"Clear Search": "清除搜索",
|
||||
"Header & Footer": "页眉页脚",
|
||||
"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?": "立即下载并安装?",
|
||||
@@ -253,7 +252,6 @@
|
||||
"Grid": "网格",
|
||||
"(from 'As You Like It', Act II)": "出自《皆大欢喜》,第二幕",
|
||||
"Link Color": "链接颜色",
|
||||
"Volume Keys for Page Flip": "音量键翻页",
|
||||
"Screen": "屏幕",
|
||||
"Orientation": "屏幕方向",
|
||||
"Portrait": "竖屏",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "开启你的书库",
|
||||
"Pick a book from your device to add it to your library.": "从设备中挑一本书加入书库吧。",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "把书拖到窗口任意位置,或从电脑中挑选一本。",
|
||||
"Sign in to sync your library": "登录以同步书库"
|
||||
"Sign in to sync your library": "登录以同步书库",
|
||||
"Clear": "清除",
|
||||
"Listening…": "监听中…",
|
||||
"Set key": "设置按键",
|
||||
"Page Turner": "翻页器",
|
||||
"Media Next": "媒体下一首",
|
||||
"Media Previous": "媒体上一首",
|
||||
"Media Play/Pause": "媒体播放/暂停",
|
||||
"Media Fast Forward": "媒体快进",
|
||||
"Media Rewind": "媒体快退",
|
||||
"Volume Up": "音量增大",
|
||||
"Volume Down": "音量减小",
|
||||
"Arrow Left": "左箭头",
|
||||
"Arrow Right": "右箭头",
|
||||
"Arrow Up": "上箭头",
|
||||
"Arrow Down": "下箭头",
|
||||
"Page Up": "向上翻页",
|
||||
"Page Down": "向下翻页",
|
||||
"Space": "空格键",
|
||||
"Enter": "回车键",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "点击「设置按键」后,按下遥控器或键盘上的按钮。",
|
||||
"Use Volume Keys": "使用音量键",
|
||||
"Custom Page Turner": "自定义翻页器"
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
"CJK Font": "中文字體",
|
||||
"Clear Search": "清除搜索",
|
||||
"Header & Footer": "頁眉頁腳",
|
||||
"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?": "立即下載並安裝?",
|
||||
@@ -252,7 +251,6 @@
|
||||
"Grid": "網格",
|
||||
"(from 'As You Like It', Act II)": "(出自《皆大歡喜》,第二幕)",
|
||||
"Link Color": "連結顏色",
|
||||
"Volume Keys for Page Flip": "音量鍵翻頁",
|
||||
"Screen": "螢幕",
|
||||
"Orientation": "螢幕方向",
|
||||
"Portrait": "豎屏",
|
||||
@@ -1387,5 +1385,27 @@
|
||||
"Start your library": "開啟你的書庫",
|
||||
"Pick a book from your device to add it to your library.": "從裝置中挑一本書加入書庫吧。",
|
||||
"Drop a book anywhere on this window, or pick one from your computer.": "把書拖到視窗任一處,或從電腦中挑選一本。",
|
||||
"Sign in to sync your library": "登入以同步書庫"
|
||||
"Sign in to sync your library": "登入以同步書庫",
|
||||
"Clear": "清除",
|
||||
"Listening…": "監聽中…",
|
||||
"Set key": "設定按鍵",
|
||||
"Page Turner": "翻頁器",
|
||||
"Media Next": "媒體下一首",
|
||||
"Media Previous": "媒體上一首",
|
||||
"Media Play/Pause": "媒體播放/暫停",
|
||||
"Media Fast Forward": "媒體快進",
|
||||
"Media Rewind": "媒體快退",
|
||||
"Volume Up": "音量增大",
|
||||
"Volume Down": "音量減小",
|
||||
"Arrow Left": "左箭頭",
|
||||
"Arrow Right": "右箭頭",
|
||||
"Arrow Up": "上箭頭",
|
||||
"Arrow Down": "下箭頭",
|
||||
"Page Up": "向上翻頁",
|
||||
"Page Down": "向下翻頁",
|
||||
"Space": "空白鍵",
|
||||
"Enter": "Enter 鍵",
|
||||
"Press a button on your remote controller or keyboard after tapping \"Set key\".": "點擊「設定按鍵」後,按下遙控器或鍵盤上的按鈕。",
|
||||
"Use Volume Keys": "使用音量鍵",
|
||||
"Custom Page Turner": "自訂翻頁器"
|
||||
}
|
||||
|
||||
+47
-8
@@ -27,6 +27,8 @@ class MainActivity : TauriActivity(), KeyDownInterceptor {
|
||||
private var wv: WebView? = null
|
||||
private var interceptVolumeKeysEnabled = false
|
||||
private var interceptBackKeyEnabled = false
|
||||
private var interceptPageTurnerKeysEnabled = false
|
||||
private var keyLearnModeEnabled = false
|
||||
|
||||
override fun onWebViewCreate(webView: WebView) {
|
||||
wv = webView
|
||||
@@ -38,6 +40,24 @@ class MainActivity : TauriActivity(), KeyDownInterceptor {
|
||||
KeyEvent.KEYCODE_VOLUME_UP to "VolumeUp"
|
||||
)
|
||||
|
||||
private val mediaKeyMap = mapOf(
|
||||
KeyEvent.KEYCODE_MEDIA_NEXT to "MediaNext",
|
||||
KeyEvent.KEYCODE_MEDIA_PREVIOUS to "MediaPrevious",
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE to "MediaPlayPause",
|
||||
KeyEvent.KEYCODE_MEDIA_FAST_FORWARD to "MediaFastForward",
|
||||
KeyEvent.KEYCODE_MEDIA_REWIND to "MediaRewind"
|
||||
)
|
||||
|
||||
private fun keyNameFor(keyCode: Int): String =
|
||||
keyEventMap[keyCode] ?: mediaKeyMap[keyCode] ?: "Keycode$keyCode"
|
||||
|
||||
private fun forwardKeyToWebView(keyName: String, keyCode: Int) {
|
||||
wv?.evaluateJavascript(
|
||||
"""try { window.onNativeKeyDown("$keyName", $keyCode); } catch (_) {}""",
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
override fun interceptVolumeKeys(enabled: Boolean) {
|
||||
Log.d("MainActivity", "Intercept volume keys: $enabled")
|
||||
interceptVolumeKeysEnabled = enabled
|
||||
@@ -48,6 +68,16 @@ class MainActivity : TauriActivity(), KeyDownInterceptor {
|
||||
interceptBackKeyEnabled = enabled
|
||||
}
|
||||
|
||||
override fun interceptPageTurnerKeys(enabled: Boolean) {
|
||||
Log.d("MainActivity", "Intercept page turner keys: $enabled")
|
||||
interceptPageTurnerKeysEnabled = enabled
|
||||
}
|
||||
|
||||
override fun setKeyLearnMode(enabled: Boolean) {
|
||||
Log.d("MainActivity", "Key learn mode: $enabled")
|
||||
keyLearnModeEnabled = enabled
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
val action = when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> "touchstart"
|
||||
@@ -93,22 +123,31 @@ class MainActivity : TauriActivity(), KeyDownInterceptor {
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
if (event.action == KeyEvent.ACTION_DOWN) {
|
||||
val keyCode = event.keyCode
|
||||
val keyName = keyEventMap[keyCode]
|
||||
|
||||
// Learn mode: forward and consume every key so the settings UI
|
||||
// can capture whatever the remote sends.
|
||||
if (keyLearnModeEnabled && keyCode != KeyEvent.KEYCODE_BACK) {
|
||||
forwardKeyToWebView(keyNameFor(keyCode), keyCode)
|
||||
return true
|
||||
}
|
||||
|
||||
// Hardware page turner: intercept media keys when enabled.
|
||||
if (interceptPageTurnerKeysEnabled && mediaKeyMap.containsKey(keyCode)) {
|
||||
forwardKeyToWebView(mediaKeyMap[keyCode]!!, keyCode)
|
||||
return true
|
||||
}
|
||||
|
||||
val keyName = keyEventMap[keyCode]
|
||||
if (keyName != null) {
|
||||
val shouldIntercept = when (keyCode) {
|
||||
KeyEvent.KEYCODE_BACK -> interceptBackKeyEnabled
|
||||
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> interceptVolumeKeysEnabled
|
||||
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN ->
|
||||
interceptVolumeKeysEnabled
|
||||
else -> false
|
||||
}
|
||||
|
||||
if (shouldIntercept) {
|
||||
wv?.evaluateJavascript(
|
||||
"""
|
||||
try { window.onNativeKeyDown("$keyName", $keyCode); } catch (_) {}
|
||||
""".trimIndent(),
|
||||
null
|
||||
)
|
||||
forwardKeyToWebView(keyName, keyCode)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+9
-10
@@ -66,6 +66,8 @@ class SetSystemUIVisibilityRequestArgs {
|
||||
class InterceptKeysRequestArgs {
|
||||
var volumeKeys: Boolean? = null
|
||||
var backKey: Boolean? = null
|
||||
var pageTurnerKeys: Boolean? = null
|
||||
var learnMode: Boolean? = null
|
||||
}
|
||||
|
||||
@InvokeArg
|
||||
@@ -115,6 +117,8 @@ data class PurchaseData(
|
||||
interface KeyDownInterceptor {
|
||||
fun interceptVolumeKeys(enabled: Boolean)
|
||||
fun interceptBackKey(enabled: Boolean)
|
||||
fun interceptPageTurnerKeys(enabled: Boolean)
|
||||
fun setKeyLearnMode(enabled: Boolean)
|
||||
}
|
||||
|
||||
@TauriPlugin(
|
||||
@@ -401,16 +405,11 @@ class NativeBridgePlugin(private val activity: Activity): Plugin(activity) {
|
||||
fun intercept_keys(invoke: Invoke) {
|
||||
val args = invoke.parseArgs(InterceptKeysRequestArgs::class.java)
|
||||
if (activity is KeyDownInterceptor) {
|
||||
when (args.backKey) {
|
||||
true -> (activity as KeyDownInterceptor).interceptBackKey(true)
|
||||
false -> (activity as KeyDownInterceptor).interceptBackKey(false)
|
||||
else -> {}
|
||||
}
|
||||
when (args.volumeKeys) {
|
||||
true -> (activity as KeyDownInterceptor).interceptVolumeKeys(true)
|
||||
false -> (activity as KeyDownInterceptor).interceptVolumeKeys(false)
|
||||
else -> {}
|
||||
}
|
||||
val interceptor = activity as KeyDownInterceptor
|
||||
args.backKey?.let { interceptor.interceptBackKey(it) }
|
||||
args.volumeKeys?.let { interceptor.interceptVolumeKeys(it) }
|
||||
args.pageTurnerKeys?.let { interceptor.interceptPageTurnerKeys(it) }
|
||||
args.learnMode?.let { interceptor.setKeyLearnMode(it) }
|
||||
} else {
|
||||
Log.e("NativeBridgePlugin", "Activity does not implement KeyDownInterceptor")
|
||||
}
|
||||
|
||||
+93
@@ -43,6 +43,8 @@ class SetSystemUIVisibilityRequestArgs: Decodable {
|
||||
class InterceptKeysRequestArgs: Decodable {
|
||||
let backKey: Bool?
|
||||
let volumeKeys: Bool?
|
||||
let pageTurnerKeys: Bool?
|
||||
let learnMode: Bool?
|
||||
}
|
||||
|
||||
class LockScreenOrientationRequestArgs: Decodable {
|
||||
@@ -192,6 +194,44 @@ class VolumeKeyHandler: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
class MediaKeyHandler {
|
||||
private weak var webView: WKWebView?
|
||||
private var registered = false
|
||||
private let commandCenter = MPRemoteCommandCenter.shared()
|
||||
|
||||
func start(webView: WKWebView) {
|
||||
self.webView = webView
|
||||
if registered { return }
|
||||
registered = true
|
||||
commandCenter.nextTrackCommand.isEnabled = true
|
||||
commandCenter.previousTrackCommand.isEnabled = true
|
||||
commandCenter.nextTrackCommand.addTarget { [weak self] _ in
|
||||
self?.forward("MediaNext")
|
||||
return .success
|
||||
}
|
||||
commandCenter.previousTrackCommand.addTarget { [weak self] _ in
|
||||
self?.forward("MediaPrevious")
|
||||
return .success
|
||||
}
|
||||
logger.log("MediaKeyHandler: started")
|
||||
}
|
||||
|
||||
func stop() {
|
||||
if !registered { return }
|
||||
registered = false
|
||||
commandCenter.nextTrackCommand.removeTarget(nil)
|
||||
commandCenter.previousTrackCommand.removeTarget(nil)
|
||||
logger.log("MediaKeyHandler: stopped")
|
||||
}
|
||||
|
||||
private func forward(_ name: String) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.webView?.evaluateJavaScript(
|
||||
"try { window.onNativeKeyDown('\(name)', 0); } catch (_) {}", completionHandler: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WebViewLifecycleManager: NSObject {
|
||||
private weak var webView: WKWebView?
|
||||
private var originalNavigationDelegate: WKNavigationDelegate?
|
||||
@@ -503,6 +543,8 @@ class NativeBridgePlugin: Plugin {
|
||||
private struct AssociatedKeys {
|
||||
static var volumeKeyHandler = "volumeKeyHandler"
|
||||
static var interceptingVolumeKeys = "interceptingVolumeKeys"
|
||||
static var mediaKeyHandler = "mediaKeyHandler"
|
||||
static var mediaKeyState = "mediaKeyState"
|
||||
}
|
||||
|
||||
private var volumeKeyHandler: VolumeKeyHandler? {
|
||||
@@ -526,6 +568,44 @@ class NativeBridgePlugin: Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
private var mediaKeyHandler: MediaKeyHandler? {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &AssociatedKeys.mediaKeyHandler) as? MediaKeyHandler
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(
|
||||
self, &AssociatedKeys.mediaKeyHandler, newValue, .OBJC_ASSOCIATION_RETAIN)
|
||||
}
|
||||
}
|
||||
|
||||
// Bit 0 = pageTurnerKeys interception, bit 1 = learn mode.
|
||||
private var mediaKeyState: Int {
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &AssociatedKeys.mediaKeyState) as? Int ?? 0
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(
|
||||
self, &AssociatedKeys.mediaKeyState, newValue, .OBJC_ASSOCIATION_RETAIN)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateMediaKeyHandler() {
|
||||
let shouldRun = mediaKeyState != 0
|
||||
if shouldRun {
|
||||
if mediaKeyHandler == nil {
|
||||
mediaKeyHandler = MediaKeyHandler()
|
||||
}
|
||||
if let webView = self.webView {
|
||||
mediaKeyHandler?.start(webView: webView)
|
||||
} else {
|
||||
logger.warning("Cannot start media key handler: webView is nil")
|
||||
}
|
||||
} else {
|
||||
mediaKeyHandler?.stop()
|
||||
mediaKeyHandler = nil
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func use_background_audio(_ invoke: Invoke) {
|
||||
do {
|
||||
let args = try invoke.parseArgs(UseBackgroundAudioRequestArgs.self)
|
||||
@@ -633,6 +713,19 @@ class NativeBridgePlugin: Plugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let pageTurnerKeys = args.pageTurnerKeys {
|
||||
mediaKeyState = pageTurnerKeys ? (mediaKeyState | 1) : (mediaKeyState & ~1)
|
||||
}
|
||||
if let learnMode = args.learnMode {
|
||||
mediaKeyState = learnMode ? (mediaKeyState | 2) : (mediaKeyState & ~2)
|
||||
}
|
||||
if args.pageTurnerKeys != nil || args.learnMode != nil {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.updateMediaKeyHandler()
|
||||
}
|
||||
}
|
||||
|
||||
invoke.resolve()
|
||||
} catch {
|
||||
invoke.reject(error.localizedDescription)
|
||||
|
||||
@@ -293,6 +293,16 @@ describe('services/constants', () => {
|
||||
expect(Array.isArray(DEFAULT_SYSTEM_SETTINGS.lastOpenBooks)).toBe(true);
|
||||
expect(DEFAULT_SYSTEM_SETTINGS.lastOpenBooks!.length).toBe(0);
|
||||
});
|
||||
|
||||
it('has a disabled hardwarePageTurner with empty bindings', () => {
|
||||
const hw = DEFAULT_SYSTEM_SETTINGS.hardwarePageTurner!;
|
||||
expect(hw).toBeDefined();
|
||||
expect(hw.enabled).toBe(false);
|
||||
expect(hw.bindings.pagePrev).toBeNull();
|
||||
expect(hw.bindings.pageNext).toBeNull();
|
||||
expect(hw.bindings.sectionPrev).toBeNull();
|
||||
expect(hw.bindings.sectionNext).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('DEFAULT_MOBILE_SYSTEM_SETTINGS', () => {
|
||||
|
||||
@@ -22,6 +22,8 @@ beforeEach(() => {
|
||||
backKeyIntercepted: false,
|
||||
volumeKeysInterceptionCount: 0,
|
||||
backKeyInterceptionCount: 0,
|
||||
pageTurnerKeysIntercepted: false,
|
||||
pageTurnerKeysInterceptionCount: 0,
|
||||
});
|
||||
vi.clearAllMocks();
|
||||
// Clean up window handlers
|
||||
@@ -224,4 +226,71 @@ describe('deviceStore', () => {
|
||||
expect(state.backKeyInterceptionCount).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
// ── Page turner key interception ───────────────────────────────
|
||||
describe('page turner key interception', () => {
|
||||
test('acquire sets state and intercepts page turner keys', async () => {
|
||||
const { interceptKeys } = await import('@/utils/bridge');
|
||||
useDeviceControlStore.getState().acquirePageTurnerKeyInterception();
|
||||
|
||||
expect(useDeviceControlStore.getState().pageTurnerKeysIntercepted).toBe(true);
|
||||
expect(useDeviceControlStore.getState().pageTurnerKeysInterceptionCount).toBe(1);
|
||||
expect(interceptKeys).toHaveBeenCalledWith({ pageTurnerKeys: true });
|
||||
});
|
||||
|
||||
test('release after single acquire stops interception', async () => {
|
||||
const { interceptKeys } = await import('@/utils/bridge');
|
||||
useDeviceControlStore.getState().acquirePageTurnerKeyInterception();
|
||||
useDeviceControlStore.getState().releasePageTurnerKeyInterception();
|
||||
|
||||
expect(useDeviceControlStore.getState().pageTurnerKeysIntercepted).toBe(false);
|
||||
expect(useDeviceControlStore.getState().pageTurnerKeysInterceptionCount).toBe(0);
|
||||
expect(interceptKeys).toHaveBeenCalledWith({ pageTurnerKeys: false });
|
||||
});
|
||||
|
||||
test('second acquire increments count without re-intercepting', async () => {
|
||||
const { interceptKeys } = await import('@/utils/bridge');
|
||||
useDeviceControlStore.getState().acquirePageTurnerKeyInterception();
|
||||
useDeviceControlStore.getState().acquirePageTurnerKeyInterception();
|
||||
|
||||
expect(useDeviceControlStore.getState().pageTurnerKeysInterceptionCount).toBe(2);
|
||||
expect(interceptKeys).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('setKeyLearnMode toggles learn mode through the bridge', async () => {
|
||||
const { interceptKeys } = await import('@/utils/bridge');
|
||||
useDeviceControlStore.getState().setKeyLearnMode(true);
|
||||
expect(interceptKeys).toHaveBeenCalledWith({ learnMode: true });
|
||||
|
||||
useDeviceControlStore.getState().setKeyLearnMode(false);
|
||||
expect(interceptKeys).toHaveBeenCalledWith({ learnMode: false });
|
||||
});
|
||||
});
|
||||
|
||||
// ── Native key forwarding ──────────────────────────────────────
|
||||
describe('handleNativeKeyDown forwarding', () => {
|
||||
test('forwards a media key through the native-key-down event', async () => {
|
||||
const { eventDispatcher } = await import('@/utils/event');
|
||||
useDeviceControlStore.getState().acquirePageTurnerKeyInterception();
|
||||
|
||||
window.onNativeKeyDown?.('MediaNext', 87);
|
||||
|
||||
expect(eventDispatcher.dispatch).toHaveBeenCalledWith('native-key-down', {
|
||||
keyName: 'MediaNext',
|
||||
keyCode: 87,
|
||||
});
|
||||
});
|
||||
|
||||
test('forwards the Back key synchronously', async () => {
|
||||
const { eventDispatcher } = await import('@/utils/event');
|
||||
useDeviceControlStore.getState().acquirePageTurnerKeyInterception();
|
||||
|
||||
window.onNativeKeyDown?.('Back', 4);
|
||||
|
||||
expect(eventDispatcher.dispatchSync).toHaveBeenCalledWith('native-key-down', {
|
||||
keyName: 'Back',
|
||||
keyCode: 4,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
normalizeNativeKey,
|
||||
normalizeDomKeyEvent,
|
||||
matchesBinding,
|
||||
resolvePageTurn,
|
||||
} from '@/utils/keybinding';
|
||||
import { HardwarePageTurnerSettings } from '@/types/settings';
|
||||
|
||||
describe('normalizeNativeKey', () => {
|
||||
test('maps a known native key to a friendly label', () => {
|
||||
expect(normalizeNativeKey('MediaNext')).toEqual({
|
||||
source: 'native',
|
||||
id: 'MediaNext',
|
||||
label: 'Media Next',
|
||||
});
|
||||
});
|
||||
|
||||
test('falls back to the raw id for an unknown native key', () => {
|
||||
expect(normalizeNativeKey('Keycode99')).toEqual({
|
||||
source: 'native',
|
||||
id: 'Keycode99',
|
||||
label: 'Keycode99',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalizeDomKeyEvent', () => {
|
||||
test('uses event.code and a friendly label for a known key', () => {
|
||||
const event = { code: 'ArrowLeft', key: 'ArrowLeft' } as KeyboardEvent;
|
||||
expect(normalizeDomKeyEvent(event)).toEqual({
|
||||
source: 'dom',
|
||||
id: 'ArrowLeft',
|
||||
label: 'Arrow Left',
|
||||
});
|
||||
});
|
||||
|
||||
test('falls back to event.key when event.code is empty', () => {
|
||||
const event = { code: '', key: 'MediaTrackNext' } as KeyboardEvent;
|
||||
expect(normalizeDomKeyEvent(event)).toEqual({
|
||||
source: 'dom',
|
||||
id: 'MediaTrackNext',
|
||||
label: 'Media Next',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('matchesBinding', () => {
|
||||
const binding = { source: 'native' as const, id: 'MediaNext', label: 'Media Next' };
|
||||
|
||||
test('matches same source and id', () => {
|
||||
expect(matchesBinding(binding, { source: 'native', id: 'MediaNext' })).toBe(true);
|
||||
});
|
||||
|
||||
test('rejects different id', () => {
|
||||
expect(matchesBinding(binding, { source: 'native', id: 'MediaPrevious' })).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects different source', () => {
|
||||
expect(matchesBinding(binding, { source: 'dom', id: 'MediaNext' })).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects a null binding', () => {
|
||||
expect(matchesBinding(null, { source: 'native', id: 'MediaNext' })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolvePageTurn', () => {
|
||||
const settings: HardwarePageTurnerSettings = {
|
||||
enabled: true,
|
||||
bindings: {
|
||||
pagePrev: { source: 'native', id: 'MediaPrevious', label: 'Media Previous' },
|
||||
pageNext: { source: 'native', id: 'MediaNext', label: 'Media Next' },
|
||||
sectionPrev: { source: 'dom', id: 'PageUp', label: 'Page Up' },
|
||||
sectionNext: { source: 'dom', id: 'PageDown', label: 'Page Down' },
|
||||
},
|
||||
};
|
||||
|
||||
test('returns "pagePrev" for the pagePrev binding', () => {
|
||||
expect(resolvePageTurn(settings, { source: 'native', id: 'MediaPrevious' })).toBe('pagePrev');
|
||||
});
|
||||
|
||||
test('returns "pageNext" for the pageNext binding', () => {
|
||||
expect(resolvePageTurn(settings, { source: 'native', id: 'MediaNext' })).toBe('pageNext');
|
||||
});
|
||||
|
||||
test('returns "sectionPrev" for the sectionPrev binding', () => {
|
||||
expect(resolvePageTurn(settings, { source: 'dom', id: 'PageUp' })).toBe('sectionPrev');
|
||||
});
|
||||
|
||||
test('returns "sectionNext" for the sectionNext binding', () => {
|
||||
expect(resolvePageTurn(settings, { source: 'dom', id: 'PageDown' })).toBe('sectionNext');
|
||||
});
|
||||
|
||||
test('returns null for an unbound key', () => {
|
||||
expect(resolvePageTurn(settings, { source: 'native', id: 'MediaPlayPause' })).toBeNull();
|
||||
});
|
||||
|
||||
test('returns null when the feature is disabled', () => {
|
||||
const disabled = { ...settings, enabled: false };
|
||||
expect(resolvePageTurn(disabled, { source: 'native', id: 'MediaNext' })).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,10 @@ import { ViewSettings } from '@/types/book';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useBookDataStore } from '@/store/bookDataStore';
|
||||
import { useDeviceControlStore } from '@/store/deviceStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useSidebarStore } from '@/store/sidebarStore';
|
||||
import { eventDispatcher } from '@/utils/event';
|
||||
import { resolvePageTurn, normalizeDomKeyEvent, KeyCandidate } from '@/utils/keybinding';
|
||||
import { isTauriAppPlatform } from '@/services/environment';
|
||||
import { tauriGetWindowLogicalPosition } from '@/utils/window';
|
||||
import { getReadingRulerMoveDirection } from '../utils/readingRuler';
|
||||
@@ -109,7 +112,15 @@ export const usePagination = (
|
||||
const { getBookData } = useBookDataStore();
|
||||
const { getViewSettings, getViewState } = useReaderStore();
|
||||
const { hoveredBookKey, setHoveredBookKey } = useReaderStore();
|
||||
const { acquireVolumeKeyInterception, releaseVolumeKeyInterception } = useDeviceControlStore();
|
||||
const {
|
||||
acquireVolumeKeyInterception,
|
||||
releaseVolumeKeyInterception,
|
||||
acquirePageTurnerKeyInterception,
|
||||
releasePageTurnerKeyInterception,
|
||||
} = useDeviceControlStore();
|
||||
// Reactive subscription: drives the effect dependency array below. The
|
||||
// handlers themselves re-read via getState() to avoid stale closures.
|
||||
const hardwarePageTurner = useSettingsStore((s) => s.settings.hardwarePageTurner);
|
||||
|
||||
const handlePageFlip = async (
|
||||
msg: MessageEvent | CustomEvent | React.MouseEvent<HTMLDivElement, MouseEvent>,
|
||||
@@ -247,6 +258,76 @@ export const usePagination = (
|
||||
}
|
||||
};
|
||||
|
||||
// Hardware page turner: media keys arrive via the `native-key-down`
|
||||
// event; D-pad / keyboard keys arrive either as a top-window `keydown`
|
||||
// or — when focus is inside a book iframe — as an `iframe-keydown`
|
||||
// postMessage (mirroring useShortcuts' unified window + iframe handling).
|
||||
// All resolve through the shared binding registry. Suppressed while the
|
||||
// toolbar is visible so D-pad keys keep driving toolbar spatial navigation.
|
||||
const handleHardwarePageTurn = (candidate: KeyCandidate): boolean => {
|
||||
const settings = useSettingsStore.getState().settings.hardwarePageTurner;
|
||||
if (!settings?.enabled) return false;
|
||||
if (useReaderStore.getState().hoveredBookKey) return false;
|
||||
|
||||
// Only the active book (the one driving the sidebar) responds, so a
|
||||
// single key press doesn't flip every book open in a parallel view.
|
||||
if (useSidebarStore.getState().sideBarBookKey !== bookKey) return false;
|
||||
|
||||
const viewState = getViewState(bookKey);
|
||||
if (!viewState?.inited) return false;
|
||||
|
||||
const action = resolvePageTurn(settings, candidate);
|
||||
if (!action) return false;
|
||||
|
||||
const viewSettings = getViewSettings(bookKey);
|
||||
const side = action === 'pagePrev' || action === 'sectionPrev' ? 'up' : 'down';
|
||||
const mode = action === 'sectionPrev' || action === 'sectionNext' ? 'section' : 'page';
|
||||
setHoveredBookKey('');
|
||||
if (
|
||||
mode === 'page' &&
|
||||
viewSettings?.readingRulerEnabled &&
|
||||
eventDispatcher.dispatchSync('reading-ruler-move', {
|
||||
bookKey,
|
||||
direction: getReadingRulerMoveDirection(side, viewRef.current?.book.dir),
|
||||
})
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
viewPagination(viewRef.current, viewSettings, side, mode);
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleHardwareNativeKey = (msg: CustomEvent) => {
|
||||
const keyName = msg.detail?.keyName;
|
||||
if (typeof keyName !== 'string') return;
|
||||
handleHardwarePageTurn({ source: 'native', id: keyName });
|
||||
};
|
||||
|
||||
const handleHardwareDomKey = (event: KeyboardEvent | MessageEvent) => {
|
||||
let candidate: KeyCandidate;
|
||||
if (event instanceof KeyboardEvent) {
|
||||
if (event.repeat) return;
|
||||
const target = event.target as HTMLElement | null;
|
||||
if (target?.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target?.tagName ?? '')) {
|
||||
return;
|
||||
}
|
||||
candidate = normalizeDomKeyEvent(event);
|
||||
} else if (event.data?.type === 'iframe-keydown' && event.data.bookKey === bookKey) {
|
||||
const id = event.data.code || event.data.key;
|
||||
if (typeof id !== 'string' || !id) return;
|
||||
candidate = { source: 'dom', id };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handleHardwarePageTurn(candidate)) {
|
||||
// Stop `useShortcuts` from also paging on this key — capture-phase
|
||||
// for the window keydown, registration order for the iframe message.
|
||||
if (event instanceof KeyboardEvent) event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!appService?.isMobileApp) return;
|
||||
|
||||
@@ -265,6 +346,45 @@ export const usePagination = (
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Hardware page turner: native-key + DOM-key listeners and native
|
||||
// media-key interception, re-evaluated whenever the setting changes.
|
||||
useEffect(() => {
|
||||
const hasNativeBinding =
|
||||
hardwarePageTurner?.bindings.pagePrev?.source === 'native' ||
|
||||
hardwarePageTurner?.bindings.pageNext?.source === 'native' ||
|
||||
hardwarePageTurner?.bindings.sectionPrev?.source === 'native' ||
|
||||
hardwarePageTurner?.bindings.sectionNext?.source === 'native';
|
||||
const needsNativeInterception =
|
||||
!!appService?.isMobileApp && !!hardwarePageTurner?.enabled && hasNativeBinding;
|
||||
|
||||
if (needsNativeInterception) {
|
||||
acquirePageTurnerKeyInterception();
|
||||
}
|
||||
if (hasNativeBinding) {
|
||||
eventDispatcher.on('native-key-down', handleHardwareNativeKey);
|
||||
}
|
||||
window.addEventListener('keydown', handleHardwareDomKey, true);
|
||||
window.addEventListener('message', handleHardwareDomKey);
|
||||
|
||||
return () => {
|
||||
if (needsNativeInterception) {
|
||||
releasePageTurnerKeyInterception();
|
||||
}
|
||||
if (hasNativeBinding) {
|
||||
eventDispatcher.off('native-key-down', handleHardwareNativeKey);
|
||||
}
|
||||
window.removeEventListener('keydown', handleHardwareDomKey, true);
|
||||
window.removeEventListener('message', handleHardwareDomKey);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
hardwarePageTurner?.enabled,
|
||||
hardwarePageTurner?.bindings.pagePrev?.source,
|
||||
hardwarePageTurner?.bindings.pageNext?.source,
|
||||
hardwarePageTurner?.bindings.sectionPrev?.source,
|
||||
hardwarePageTurner?.bindings.sectionNext?.source,
|
||||
]);
|
||||
|
||||
// Touch swipe page flip for fixed-layout books — registered as a touch interceptor
|
||||
// so it participates in the priority-based consumption chain.
|
||||
useTouchInterceptor(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useDeviceControlStore } from '@/store/deviceStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useBookDataStore } from '@/store/bookDataStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
@@ -14,6 +13,7 @@ import { SettingsPanelPanelProp } from './SettingsDialog';
|
||||
import { annotationToolQuickActions } from '@/app/reader/components/annotator/AnnotationTools';
|
||||
import { BoxedList, SettingsRow, SettingsSelect, SettingsSwitchRow } from './primitives';
|
||||
import NumberInput from './NumberInput';
|
||||
import PageTurnerSettings from './PageTurnerSettings';
|
||||
|
||||
const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset }) => {
|
||||
const _ = useTranslation();
|
||||
@@ -22,7 +22,6 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
const { getBookData } = useBookDataStore();
|
||||
const { settings } = useSettingsStore();
|
||||
const { applyEinkMode } = useEinkMode();
|
||||
const { acquireVolumeKeyInterception, releaseVolumeKeyInterception } = useDeviceControlStore();
|
||||
const bookData = getBookData(bookKey);
|
||||
const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings;
|
||||
|
||||
@@ -30,7 +29,6 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
const [noContinuousScroll, setNoContinuousScroll] = useState(viewSettings.noContinuousScroll);
|
||||
const [scrollingOverlap, setScrollingOverlap] = useState(viewSettings.scrollingOverlap);
|
||||
const [hideScrollbar, setHideScrollbar] = useState(viewSettings.hideScrollbar || false);
|
||||
const [volumeKeysToFlip, setVolumeKeysToFlip] = useState(viewSettings.volumeKeysToFlip);
|
||||
const [showPaginationButtons, setShowPaginationButtons] = useState(
|
||||
viewSettings.showPaginationButtons,
|
||||
);
|
||||
@@ -53,6 +51,7 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
const [allowScript, setAllowScript] = useState(viewSettings.allowScript);
|
||||
|
||||
const resetToDefaults = useResetViewSettings();
|
||||
const pageTurnerResetRef = useRef<() => void>(() => {});
|
||||
|
||||
const handleReset = () => {
|
||||
resetToDefaults({
|
||||
@@ -60,7 +59,6 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
noContinuousScroll: setNoContinuousScroll,
|
||||
scrollingOverlap: setScrollingOverlap,
|
||||
hideScrollbar: setHideScrollbar,
|
||||
volumeKeysToFlip: setVolumeKeysToFlip,
|
||||
showPaginationButtons: setShowPaginationButtons,
|
||||
disableClick: setIsDisableClick,
|
||||
swapClickArea: setSwapClickArea,
|
||||
@@ -72,6 +70,7 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
enableAnnotationQuickActions: setEnableAnnotationQuickActions,
|
||||
copyToNotebook: setCopyToNotebook,
|
||||
});
|
||||
pageTurnerResetRef.current();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -113,18 +112,6 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [scrollingOverlap]);
|
||||
|
||||
useEffect(() => {
|
||||
saveViewSettings(envConfig, bookKey, 'volumeKeysToFlip', volumeKeysToFlip, false, false);
|
||||
if (appService?.isMobileApp) {
|
||||
if (volumeKeysToFlip) {
|
||||
acquireVolumeKeyInterception();
|
||||
} else {
|
||||
releaseVolumeKeyInterception();
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [volumeKeysToFlip]);
|
||||
|
||||
useEffect(() => {
|
||||
saveViewSettings(
|
||||
envConfig,
|
||||
@@ -300,13 +287,6 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
onChange={() => setIsDisableDoubleClick(!isDisableDoubleClick)}
|
||||
data-setting-id='settings.control.disableDoubleClick'
|
||||
/>
|
||||
{appService?.isMobileApp && (
|
||||
<SettingsSwitchRow
|
||||
label={_('Volume Keys for Page Flip')}
|
||||
checked={volumeKeysToFlip}
|
||||
onChange={() => setVolumeKeysToFlip(!volumeKeysToFlip)}
|
||||
/>
|
||||
)}
|
||||
<SettingsSwitchRow
|
||||
label={_('Show Page Navigation Buttons')}
|
||||
checked={showPaginationButtons}
|
||||
@@ -315,6 +295,13 @@ const ControlPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterRes
|
||||
/>
|
||||
</BoxedList>
|
||||
|
||||
<PageTurnerSettings
|
||||
bookKey={bookKey}
|
||||
onRegisterReset={(fn) => {
|
||||
pageTurnerResetRef.current = fn;
|
||||
}}
|
||||
/>
|
||||
|
||||
<BoxedList
|
||||
title={_('Annotation Tools')}
|
||||
data-setting-id='settings.control.enableQuickActions'
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useDeviceControlStore } from '@/store/deviceStore';
|
||||
import { saveSysSettings, saveViewSettings } from '@/helpers/settings';
|
||||
import { useResetViewSettings } from '@/hooks/useResetSettings';
|
||||
import { eventDispatcher } from '@/utils/event';
|
||||
import {
|
||||
normalizeNativeKey,
|
||||
normalizeDomKeyEvent,
|
||||
PAGE_TURN_ACTIONS,
|
||||
PageTurnAction,
|
||||
} from '@/utils/keybinding';
|
||||
import { HardwarePageTurnerSettings, KeyBinding } from '@/types/settings';
|
||||
import { BoxedList, SettingsRow, SettingsSwitchRow } from './primitives';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
|
||||
type Slot = PageTurnAction;
|
||||
const LEARN_TIMEOUT_MS = 8000;
|
||||
|
||||
interface PageTurnerSettingsProps {
|
||||
bookKey: string;
|
||||
onRegisterReset?: (resetFn: () => void) => void;
|
||||
}
|
||||
|
||||
const PageTurnerSettings: React.FC<PageTurnerSettingsProps> = ({ bookKey, onRegisterReset }) => {
|
||||
const _ = useTranslation();
|
||||
const { envConfig, appService } = useEnv();
|
||||
const { getViewSettings } = useReaderStore();
|
||||
const { setKeyLearnMode, acquireVolumeKeyInterception, releaseVolumeKeyInterception } =
|
||||
useDeviceControlStore();
|
||||
const { settings } = useSettingsStore();
|
||||
const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings;
|
||||
const resetToDefaults = useResetViewSettings();
|
||||
|
||||
const [volumeKeysToFlip, setVolumeKeysToFlip] = useState(viewSettings.volumeKeysToFlip);
|
||||
const [config, setConfig] = useState<HardwarePageTurnerSettings>(settings.hardwarePageTurner);
|
||||
const configRef = useRef(config);
|
||||
configRef.current = config;
|
||||
const [listening, setListening] = useState<Slot | null>(null);
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
const persist = (next: HardwarePageTurnerSettings) => {
|
||||
setConfig(next);
|
||||
saveSysSettings(envConfig, 'hardwarePageTurner', next);
|
||||
};
|
||||
|
||||
// Native key interception exists only on mobile; on web and desktop
|
||||
// learn mode relies on standard DOM keydown events alone.
|
||||
const setNativeLearnMode = (enabled: boolean) => {
|
||||
if (appService?.isMobileApp) setKeyLearnMode(enabled);
|
||||
};
|
||||
|
||||
const stopListening = () => {
|
||||
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
setNativeLearnMode(false);
|
||||
setListening(null);
|
||||
};
|
||||
|
||||
const captureBinding = (slot: Slot, binding: KeyBinding) => {
|
||||
const current = configRef.current;
|
||||
const bindings = { ...current.bindings, [slot]: binding };
|
||||
// A key can drive only one action — clear it from every other slot.
|
||||
for (const other of PAGE_TURN_ACTIONS) {
|
||||
if (
|
||||
other !== slot &&
|
||||
bindings[other]?.source === binding.source &&
|
||||
bindings[other]?.id === binding.id
|
||||
) {
|
||||
bindings[other] = null;
|
||||
}
|
||||
}
|
||||
persist({ ...current, bindings });
|
||||
stopListening();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!listening) return;
|
||||
|
||||
const onNativeKey = (msg: CustomEvent) => {
|
||||
const keyName = msg.detail?.keyName;
|
||||
if (typeof keyName !== 'string') return;
|
||||
// Back, and volume keys (which have their own dedicated page-flip
|
||||
// toggle), are not bindable here — binding them would be inert or
|
||||
// would double-fire alongside the volume-keys handler.
|
||||
if (keyName === 'Back' || keyName === 'VolumeUp' || keyName === 'VolumeDown') return;
|
||||
captureBinding(listening, normalizeNativeKey(keyName));
|
||||
};
|
||||
const onDomKey = (event: KeyboardEvent) => {
|
||||
if (event.repeat) return;
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
captureBinding(listening, normalizeDomKeyEvent(event));
|
||||
};
|
||||
|
||||
setNativeLearnMode(true);
|
||||
eventDispatcher.on('native-key-down', onNativeKey);
|
||||
window.addEventListener('keydown', onDomKey, true);
|
||||
timeoutRef.current = setTimeout(stopListening, LEARN_TIMEOUT_MS);
|
||||
|
||||
return () => {
|
||||
eventDispatcher.off('native-key-down', onNativeKey);
|
||||
window.removeEventListener('keydown', onDomKey, true);
|
||||
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
||||
timeoutRef.current = null;
|
||||
setNativeLearnMode(false);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [listening]);
|
||||
|
||||
useEffect(() => {
|
||||
saveViewSettings(envConfig, bookKey, 'volumeKeysToFlip', volumeKeysToFlip, false, false);
|
||||
if (appService?.isMobileApp) {
|
||||
if (volumeKeysToFlip) {
|
||||
acquireVolumeKeyInterception();
|
||||
} else {
|
||||
releaseVolumeKeyInterception();
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [volumeKeysToFlip]);
|
||||
|
||||
useEffect(() => {
|
||||
onRegisterReset?.(() => resetToDefaults({ volumeKeysToFlip: setVolumeKeysToFlip }));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!config.enabled && listening) stopListening();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [config.enabled]);
|
||||
|
||||
const renderSlot = (slot: Slot, label: string) => {
|
||||
const binding = config.bindings[slot];
|
||||
const isListening = listening === slot;
|
||||
return (
|
||||
<SettingsRow
|
||||
label={label}
|
||||
disabled={!config.enabled}
|
||||
data-setting-id={`settings.control.pageTurner.${slot}`}
|
||||
>
|
||||
<div className='flex items-center gap-5'>
|
||||
{binding && !isListening && (
|
||||
<button
|
||||
type='button'
|
||||
className='text-base-content/70 hover:text-base-content text-end text-[0.85em] focus:outline-none'
|
||||
disabled={!config.enabled}
|
||||
aria-label={`${_('Clear')}: ${label}`}
|
||||
onClick={() => persist({ ...config, bindings: { ...config.bindings, [slot]: null } })}
|
||||
>
|
||||
{_('Clear')}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type='button'
|
||||
className='text-base-content/70 hover:text-base-content py-1 text-end text-[0.85em] focus:outline-none'
|
||||
disabled={!config.enabled}
|
||||
aria-pressed={isListening}
|
||||
aria-label={`${label}: ${isListening ? _('Listening…') : _('Set key')}`}
|
||||
onClick={() => (isListening ? stopListening() : setListening(slot))}
|
||||
>
|
||||
{isListening ? _('Listening…') : binding ? _(binding.label) : _('Set key')}
|
||||
</button>
|
||||
</div>
|
||||
</SettingsRow>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='space-y-2'>
|
||||
<BoxedList
|
||||
title={_('Page Turner')}
|
||||
data-setting-id='settings.control.pageTurner'
|
||||
description={_(
|
||||
'Press a button on your remote controller or keyboard after tapping "Set key".',
|
||||
)}
|
||||
>
|
||||
{appService?.isMobileApp && (
|
||||
<SettingsSwitchRow
|
||||
label={_('Use Volume Keys')}
|
||||
checked={volumeKeysToFlip}
|
||||
onChange={() => setVolumeKeysToFlip(!volumeKeysToFlip)}
|
||||
/>
|
||||
)}
|
||||
<SettingsSwitchRow
|
||||
label={_('Custom Page Turner')}
|
||||
checked={config.enabled}
|
||||
onChange={() => persist({ ...config, enabled: !config.enabled })}
|
||||
/>
|
||||
{renderSlot('pagePrev', _('Previous Page'))}
|
||||
{renderSlot('pageNext', _('Next Page'))}
|
||||
{renderSlot('sectionPrev', _('Previous Section'))}
|
||||
{renderSlot('sectionNext', _('Next Section'))}
|
||||
</BoxedList>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageTurnerSettings;
|
||||
@@ -42,14 +42,14 @@ const BoxedList: React.FC<BoxedListProps> = ({
|
||||
return (
|
||||
<div className={clsx('w-full', className)} data-setting-id={dataSettingId}>
|
||||
{title && <SectionTitle className='mb-2'>{title}</SectionTitle>}
|
||||
{description && (
|
||||
<p className='text-base-content/65 -mt-1 mb-2 text-[0.7em] leading-relaxed'>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
<div className={clsx('card eink-bordered border-base-200 bg-base-100 border', cardClassName)}>
|
||||
<div className={clsx('divide-base-200 divide-y ps-4', innerClassName)}>{children}</div>
|
||||
</div>
|
||||
{description && (
|
||||
<p className='text-base-content/65 mb-2 mt-1 ps-4 text-[0.8em] leading-relaxed'>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -94,6 +94,10 @@ export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
|
||||
screenWakeLock: false,
|
||||
screenBrightness: -1, // -1~100, -1 for system default
|
||||
autoScreenBrightness: true,
|
||||
hardwarePageTurner: {
|
||||
enabled: false,
|
||||
bindings: { pagePrev: null, pageNext: null, sectionPrev: null, sectionNext: null },
|
||||
},
|
||||
openLastBooks: false,
|
||||
lastOpenBooks: [],
|
||||
autoImportBooksOnOpen: false,
|
||||
|
||||
@@ -5,19 +5,19 @@ import { NativeTouchEventType } from '@/types/system';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
onNativeKeyDown?: (keyName: string) => void;
|
||||
onNativeKeyDown?: (keyName: string, keyCode?: number) => void;
|
||||
onNativeTouch?: (event: NativeTouchEventType) => void;
|
||||
}
|
||||
}
|
||||
|
||||
const handleNativeKeyDown = (keyName: string) => {
|
||||
if (keyName === 'VolumeUp' || keyName === 'VolumeDown') {
|
||||
return eventDispatcher.dispatch('native-key-down', { keyName });
|
||||
}
|
||||
const handleNativeKeyDown = (keyName: string, keyCode?: number) => {
|
||||
// Back is handled synchronously so dialogs can consume it before it
|
||||
// bubbles; every other key (volume, media, learn-mode captures) is
|
||||
// dispatched asynchronously through the same channel.
|
||||
if (keyName === 'Back') {
|
||||
return eventDispatcher.dispatchSync('native-key-down', { keyName });
|
||||
return eventDispatcher.dispatchSync('native-key-down', { keyName, keyCode });
|
||||
}
|
||||
return false;
|
||||
return eventDispatcher.dispatch('native-key-down', { keyName, keyCode });
|
||||
};
|
||||
|
||||
type DeviceControlState = {
|
||||
@@ -31,6 +31,11 @@ type DeviceControlState = {
|
||||
releaseVolumeKeyInterception: () => void;
|
||||
acquireBackKeyInterception: () => void;
|
||||
releaseBackKeyInterception: () => void;
|
||||
pageTurnerKeysIntercepted: boolean;
|
||||
pageTurnerKeysInterceptionCount: number;
|
||||
acquirePageTurnerKeyInterception: () => void;
|
||||
releasePageTurnerKeyInterception: () => void;
|
||||
setKeyLearnMode: (enabled: boolean) => void;
|
||||
listenToNativeTouchEvents: () => void;
|
||||
};
|
||||
|
||||
@@ -39,6 +44,8 @@ export const useDeviceControlStore = create<DeviceControlState>((set, get) => ({
|
||||
backKeyIntercepted: false,
|
||||
volumeKeysInterceptionCount: 0,
|
||||
backKeyInterceptionCount: 0,
|
||||
pageTurnerKeysIntercepted: false,
|
||||
pageTurnerKeysInterceptionCount: 0,
|
||||
|
||||
acquireVolumeKeyInterception: () => {
|
||||
const { volumeKeysInterceptionCount } = get();
|
||||
@@ -80,6 +87,33 @@ export const useDeviceControlStore = create<DeviceControlState>((set, get) => ({
|
||||
}
|
||||
},
|
||||
|
||||
acquirePageTurnerKeyInterception: () => {
|
||||
const { pageTurnerKeysInterceptionCount } = get();
|
||||
if (pageTurnerKeysInterceptionCount == 0) {
|
||||
window.onNativeKeyDown = handleNativeKeyDown;
|
||||
interceptKeys({ pageTurnerKeys: true });
|
||||
set({ pageTurnerKeysIntercepted: true });
|
||||
}
|
||||
set({ pageTurnerKeysInterceptionCount: pageTurnerKeysInterceptionCount + 1 });
|
||||
},
|
||||
|
||||
releasePageTurnerKeyInterception: () => {
|
||||
const { pageTurnerKeysInterceptionCount } = get();
|
||||
if (pageTurnerKeysInterceptionCount <= 1) {
|
||||
interceptKeys({ pageTurnerKeys: false });
|
||||
set({ pageTurnerKeysIntercepted: false, pageTurnerKeysInterceptionCount: 0 });
|
||||
} else {
|
||||
set({ pageTurnerKeysInterceptionCount: pageTurnerKeysInterceptionCount - 1 });
|
||||
}
|
||||
},
|
||||
|
||||
// Learn mode is a stateless UI toggle (used while capturing a binding),
|
||||
// not reference-counted like the acquire/release interception actions.
|
||||
setKeyLearnMode: (enabled: boolean) => {
|
||||
window.onNativeKeyDown = handleNativeKeyDown;
|
||||
interceptKeys({ learnMode: enabled });
|
||||
},
|
||||
|
||||
listenToNativeTouchEvents: () => {
|
||||
window.onNativeTouch = (event: NativeTouchEventType) => {
|
||||
return eventDispatcher.dispatch('native-touch', event);
|
||||
|
||||
@@ -111,6 +111,25 @@ export const SYNC_CATEGORIES: readonly SyncCategory[] = [
|
||||
'credentials',
|
||||
] as const;
|
||||
|
||||
export interface KeyBinding {
|
||||
/** `native` = media keys forwarded by the OS bridge; `dom` = keyboard/D-pad keys. */
|
||||
source: 'native' | 'dom';
|
||||
/** Native key name (e.g. `MediaNext`) or DOM `event.code` (e.g. `ArrowLeft`). */
|
||||
id: string;
|
||||
/** Human-readable label shown in settings. */
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface HardwarePageTurnerSettings {
|
||||
enabled: boolean;
|
||||
bindings: {
|
||||
pagePrev: KeyBinding | null;
|
||||
pageNext: KeyBinding | null;
|
||||
sectionPrev: KeyBinding | null;
|
||||
sectionNext: KeyBinding | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SystemSettings {
|
||||
version: number;
|
||||
migrationVersion: number;
|
||||
@@ -125,6 +144,7 @@ export interface SystemSettings {
|
||||
screenWakeLock: boolean;
|
||||
screenBrightness: number;
|
||||
autoScreenBrightness: boolean;
|
||||
hardwarePageTurner: HardwarePageTurnerSettings;
|
||||
alwaysShowStatusBar: boolean;
|
||||
alwaysInForeground: boolean;
|
||||
openLastBooks: boolean;
|
||||
|
||||
@@ -46,6 +46,10 @@ export interface GetSystemFontsListResponse {
|
||||
export interface InterceptKeysRequest {
|
||||
volumeKeys?: boolean;
|
||||
backKey?: boolean;
|
||||
/** Intercept media keys (next/previous/play-pause) for the hardware page turner. */
|
||||
pageTurnerKeys?: boolean;
|
||||
/** Forward every key press to JS so the settings UI can capture a binding. */
|
||||
learnMode?: boolean;
|
||||
}
|
||||
|
||||
export interface LockScreenRequest {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { HardwarePageTurnerSettings, KeyBinding } from '@/types/settings';
|
||||
import { stubTranslation as _ } from '@/utils/misc';
|
||||
|
||||
export type KeyCandidate = { source: 'native' | 'dom'; id: string };
|
||||
export type PageTurnAction = 'pagePrev' | 'pageNext' | 'sectionPrev' | 'sectionNext';
|
||||
|
||||
export const PAGE_TURN_ACTIONS: PageTurnAction[] = [
|
||||
'pagePrev',
|
||||
'pageNext',
|
||||
'sectionPrev',
|
||||
'sectionNext',
|
||||
];
|
||||
|
||||
const NATIVE_KEY_LABELS: Record<string, string> = {
|
||||
MediaNext: _('Media Next'),
|
||||
MediaPrevious: _('Media Previous'),
|
||||
MediaPlayPause: _('Media Play/Pause'),
|
||||
MediaFastForward: _('Media Fast Forward'),
|
||||
MediaRewind: _('Media Rewind'),
|
||||
VolumeUp: _('Volume Up'),
|
||||
VolumeDown: _('Volume Down'),
|
||||
};
|
||||
|
||||
const DOM_KEY_LABELS: Record<string, string> = {
|
||||
ArrowLeft: _('Arrow Left'),
|
||||
ArrowRight: _('Arrow Right'),
|
||||
ArrowUp: _('Arrow Up'),
|
||||
ArrowDown: _('Arrow Down'),
|
||||
PageUp: _('Page Up'),
|
||||
PageDown: _('Page Down'),
|
||||
Space: _('Space'),
|
||||
Enter: _('Enter'),
|
||||
MediaTrackNext: _('Media Next'),
|
||||
MediaTrackPrevious: _('Media Previous'),
|
||||
MediaPlayPause: _('Media Play/Pause'),
|
||||
};
|
||||
|
||||
/** Normalize a native key name (from the OS bridge) into a `KeyBinding`. */
|
||||
export const normalizeNativeKey = (name: string): KeyBinding => ({
|
||||
source: 'native',
|
||||
id: name,
|
||||
label: NATIVE_KEY_LABELS[name] ?? name,
|
||||
});
|
||||
|
||||
/** Normalize a DOM `KeyboardEvent` into a `KeyBinding`. */
|
||||
export const normalizeDomKeyEvent = (event: KeyboardEvent): KeyBinding => {
|
||||
const id = event.code || event.key;
|
||||
return {
|
||||
source: 'dom',
|
||||
id,
|
||||
label: DOM_KEY_LABELS[id] ?? id,
|
||||
};
|
||||
};
|
||||
|
||||
/** True when `candidate` is the key described by `binding`. */
|
||||
export const matchesBinding = (binding: KeyBinding | null, candidate: KeyCandidate): boolean =>
|
||||
!!binding && binding.source === candidate.source && binding.id === candidate.id;
|
||||
|
||||
/**
|
||||
* Decide which page-turn action an incoming key triggers. Returns the
|
||||
* action, or `null` when the feature is disabled or the key is unbound.
|
||||
*/
|
||||
export const resolvePageTurn = (
|
||||
settings: HardwarePageTurnerSettings,
|
||||
candidate: KeyCandidate,
|
||||
): PageTurnAction | null => {
|
||||
if (!settings.enabled) return null;
|
||||
for (const action of PAGE_TURN_ACTIONS) {
|
||||
if (matchesBinding(settings.bindings[action], candidate)) return action;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
Reference in New Issue
Block a user