forked from akai/readest
- Sync library-scope replacement rules across devices (settings whitelist). Book and selection rules already ride along the book config. - Add regex support: a Regex toggle on the selection popup plus a full add-rule form (find / replace / scope / regex / case-sensitive) in the Proofread Rules manager. - Reuse Ctrl/Cmd+P to open the rules manager when nothing is selected (handleProofread); opens the create-from-selection popup otherwise. - Translate the whole-word warning, which was hardcoded English. - Drag-to-reorder rules within each category (dnd-kit), persisted via the rule order field across both the book config and global settings. - Modernize the manager dialog with the settings primitives and a btn-contrast CTA; fix mobile height clipping and the inset scrollbar. - Translate all pending i18n strings across 33 locales (includes the delete-confirm strings surfaced by the extractor). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -464,6 +464,7 @@
|
||||
"TTS not supported for this document": "تكنولوجيا تحويل النص إلى كلام غير مدعومة لهذا المستند.",
|
||||
"Reset Password": "إعادة تعيين",
|
||||
"Show Reading Progress": "إظهار تقدم القراءة",
|
||||
"Show Progress Bar": "إظهار شريط التقدم",
|
||||
"Reading Progress Style": "نمط تقدم القراءة",
|
||||
"Page Number": "رقم الصفحة",
|
||||
"Percentage": "النسبة المئوية",
|
||||
@@ -1890,10 +1891,6 @@
|
||||
"Auto Sync": "مزامنة تلقائية",
|
||||
"Purged book data: {{title}}": "تم محو بيانات الكتاب: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "فشل محو بيانات الكتاب: {{title}}",
|
||||
"Purge Book Data": "محو جميع بيانات الكتاب",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "سيؤدي هذا إلى محو الكتاب وجميع بياناته نهائيًا، بما في ذلك تقدم القراءة والملاحظات والإشارات المرجعية. لا يمكن التراجع عن هذا الإجراء.",
|
||||
"Purge Data": "محو جميع البيانات",
|
||||
"Erase the book and all its data, including reading progress": "محو الكتاب وجميع بياناته، بما في ذلك تقدم القراءة",
|
||||
"More Actions": "إجراءات أخرى",
|
||||
"Sign in and make the book available to share it": "سجّل الدخول واجعل الكتاب متاحًا لمشاركته",
|
||||
"Download the book to export it": "نزّل الكتاب لتصديره",
|
||||
@@ -1912,5 +1909,16 @@
|
||||
"Failed to save the image": "فشل حفظ الصورة",
|
||||
"Share Image": "مشاركة الصورة",
|
||||
"Save Image": "حفظ الصورة",
|
||||
"Image saved to gallery": "تم حفظ الصورة في المعرض"
|
||||
"Image saved to gallery": "تم حفظ الصورة في المعرض",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "يرجى تحديد كلمة كاملة أو إلغاء تحديد خيار \"كلمة كاملة\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "تعبير نمطي غير صالح",
|
||||
"Find pattern cannot be empty": "لا يمكن أن يكون نمط البحث فارغًا",
|
||||
"Add Rule": "إضافة قاعدة",
|
||||
"Find...": "بحث...",
|
||||
"Replace with...": "استبدال بـ...",
|
||||
"Purge & Delete": "مسح وحذف",
|
||||
"Purge all reading data": "مسح جميع بيانات القراءة",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "يؤدي هذا إلى مسح تقدم القراءة والملاحظات والإشارات المرجعية نهائيًا. لا يمكن التراجع عن هذا الإجراء.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "يمسح أيضًا تقدم القراءة والملاحظات والإشارات المرجعية."
|
||||
}
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
"Show Remaining Time": "বাকি সময় দেখান",
|
||||
"Show Remaining Pages": "বাকি পৃষ্ঠা দেখান",
|
||||
"Show Reading Progress": "পড়ার অগ্রগতি দেখান",
|
||||
"Show Progress Bar": "অগ্রগতি বার দেখান",
|
||||
"Reading Progress Style": "পড়ার অগ্রগতির স্টাইল",
|
||||
"Page Number": "পৃষ্ঠা নম্বর",
|
||||
"Percentage": "শতাংশ",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "স্বয়ংক্রিয় সিঙ্ক",
|
||||
"Purged book data: {{title}}": "বইয়ের ডেটা মুছে ফেলা হয়েছে: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "বইয়ের ডেটা মুছতে ব্যর্থ: {{title}}",
|
||||
"Purge Book Data": "বইয়ের সমস্ত ডেটা মুছুন",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "এটি বইটি এবং পড়ার অগ্রগতি, নোট ও বুকমার্ক সহ এর সমস্ত ডেটা স্থায়ীভাবে মুছে ফেলবে। এটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"Purge Data": "সমস্ত ডেটা মুছুন",
|
||||
"Erase the book and all its data, including reading progress": "পড়ার অগ্রগতিসহ বই ও এর সমস্ত ডেটা মুছে ফেলুন",
|
||||
"More Actions": "আরও ক্রিয়া",
|
||||
"Sign in and make the book available to share it": "শেয়ার করতে সাইন ইন করুন এবং বইটি উপলব্ধ করুন",
|
||||
"Download the book to export it": "এক্সপোর্ট করতে বইটি ডাউনলোড করুন",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "ছবি সংরক্ষণ করা যায়নি",
|
||||
"Share Image": "ছবি শেয়ার করুন",
|
||||
"Save Image": "ছবি সংরক্ষণ করুন",
|
||||
"Image saved to gallery": "ছবি গ্যালারিতে সংরক্ষিত হয়েছে"
|
||||
"Image saved to gallery": "ছবি গ্যালারিতে সংরক্ষিত হয়েছে",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "একটি সম্পূর্ণ শব্দ নির্বাচন করুন অথবা \"সম্পূর্ণ শব্দ\" বিকল্পটি আনচেক করুন।",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "অবৈধ রেগুলার এক্সপ্রেশন",
|
||||
"Find pattern cannot be empty": "অনুসন্ধান প্যাটার্ন খালি রাখা যাবে না",
|
||||
"Add Rule": "নিয়ম যোগ করুন",
|
||||
"Find...": "খুঁজুন...",
|
||||
"Replace with...": "প্রতিস্থাপন করুন...",
|
||||
"Purge & Delete": "পরিষ্কার করে মুছুন",
|
||||
"Purge all reading data": "সমস্ত পড়ার ডেটা পরিষ্কার করুন",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "এটি স্থায়ীভাবে পড়ার অগ্রগতি, নোট এবং বুকমার্ক মুছে ফেলে। এটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"Also erase reading progress, notes, and bookmarks.": "পড়ার অগ্রগতি, নোট এবং বুকমার্কও মুছে ফেলে।"
|
||||
}
|
||||
|
||||
@@ -443,6 +443,7 @@
|
||||
"TTS not supported for this document": "ཡིག་ཆ་འདིར་ TTS རྒྱབ་སྐྱོར་མི་བྱེད།",
|
||||
"Reset Password": "གསང་ཨང་བསྐྱར་སྒྲིག",
|
||||
"Show Reading Progress": "ཀློག་པའི་ཡར་འཕེལ་མངོན་པ།",
|
||||
"Show Progress Bar": "ཡར་འཕེལ་ཕྲ་རིང་མངོན་པ།",
|
||||
"Reading Progress Style": "ཀློག་པའི་ཡར་འཕེལ་གྱི་རྣམ་པ།",
|
||||
"Page Number": "ཤོག་ཨང་།",
|
||||
"Percentage": "བརྒྱ་ཆ།",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "རང་འགུལ་སྤྲི་དོན།",
|
||||
"Purged book data: {{title}}": "དཔེ་དེབ་ཀྱི་གཞི་གྲངས་བསུབ་ཟིན། {{title}}",
|
||||
"Failed to purge book data: {{title}}": "དཔེ་དེབ་ཀྱི་གཞི་གྲངས་བསུབ་མ་ཐུབ། {{title}}",
|
||||
"Purge Book Data": "དཔེ་དེབ་ཀྱི་གཞི་གྲངས་ཡོངས་སུ་བསུབ།",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "འདིས་དཔེ་དེབ་དང་ཀློག་འདོན་གྱི་འཕེལ་རིམ། ཟིན་ཐོ། དེབ་རྟགས་བཅས་ཀྱི་གཞི་གྲངས་ཡོངས་རྫོགས་གཏན་འཁེལ་དུ་བསུབ་པ་ཡིན། འདི་ཕྱིར་བསྒྱུར་མི་ཐུབ།",
|
||||
"Purge Data": "གཞི་གྲངས་ཡོངས་སུ་བསུབ།",
|
||||
"Erase the book and all its data, including reading progress": "དཔེ་དེབ་དང་ཀློག་འདོན་གྱི་འཕེལ་རིམ་བཅས་ཀྱི་གཞི་གྲངས་ཡོངས་སུ་བསུབ།",
|
||||
"More Actions": "བྱ་སྤྱོད་གཞན་དག",
|
||||
"Sign in and make the book available to share it": "ནང་འཛུལ་བྱས་ནས་དཔེ་དེབ་མཁོ་སྤྲོད་རུང་བར་བཟོས་ནས་མཉམ་སྤྱོད་བྱོས།",
|
||||
"Download the book to export it": "ཕྱིར་འདྲེན་བྱེད་པར་དཔེ་དེབ་ཕབ་ལེན་བྱོས།",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "པར་རིས་ཉར་ཚགས་བྱས་མ་ཐུབ",
|
||||
"Share Image": "པར་རིས་མཉམ་སྤྱོད།",
|
||||
"Save Image": "པར་རིས་ཉར་ཚགས།",
|
||||
"Image saved to gallery": "པར་རིས་པར་མཛོད་ནང་ཉར་ཚགས་བྱས་ཟིན"
|
||||
"Image saved to gallery": "པར་རིས་པར་མཛོད་ནང་ཉར་ཚགས་བྱས་ཟིན",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "ཡིག་འབྲུ་ཆ་ཚང་ཞིག་འདེམས་རོགས། ཡང་ན་ \"ཚིག་གྲུབ་ཆ་ཚང་\" ཞེས་པའི་གདམ་ག་ཕྱིར་འཐེན་གནང་རོགས།",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Regex ནུས་མེད་རེད།",
|
||||
"Find pattern cannot be empty": "འཚོལ་བཤེར་དཔེ་རིས་སྟོང་པ་ཡིན་མི་ཆོག",
|
||||
"Add Rule": "སྒྲིག་གཞི་ཁ་སྣོན།",
|
||||
"Find...": "འཚོལ་བཤེར།...",
|
||||
"Replace with...": "བརྗེ་བ།...",
|
||||
"Purge & Delete": "གཙང་སེལ་བྱས་ནས་སུབ་པ།",
|
||||
"Purge all reading data": "ཀློག་པའི་གཞི་གྲངས་ཡོངས་གཙང་སེལ།",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "འདིས་ཀློག་པའི་ཡར་འཕེལ་དང་། ཟིན་བྲིས། དཔེ་རྟགས་བཅས་གཏན་དུ་སུབ་ངེས་ཡིན། ཕྱིར་ལྡོག་བྱེད་མི་ཐུབ།",
|
||||
"Also erase reading progress, notes, and bookmarks.": "ཀློག་པའི་ཡར་འཕེལ་དང་། ཟིན་བྲིས། དཔེ་རྟགས་བཅས་ཀྱང་སུབ་པ།"
|
||||
}
|
||||
|
||||
@@ -448,6 +448,7 @@
|
||||
"TTS not supported for this document": "TTS wird für dieses Dokument nicht unterstützt",
|
||||
"Reset Password": "Passwort zurücksetzen",
|
||||
"Show Reading Progress": "Lesefortschritt anzeigen",
|
||||
"Show Progress Bar": "Fortschrittsleiste anzeigen",
|
||||
"Reading Progress Style": "Lesefortschritt-Stil",
|
||||
"Page Number": "Seitenzahl",
|
||||
"Percentage": "Prozentsatz",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "Automatische Synchronisierung",
|
||||
"Purged book data: {{title}}": "Buchdaten gelöscht: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Buchdaten konnten nicht gelöscht werden: {{title}}",
|
||||
"Purge Book Data": "Buchdaten endgültig löschen",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Dadurch werden das Buch und alle zugehörigen Daten – einschließlich Lesefortschritt, Notizen und Lesezeichen – endgültig gelöscht. Dies kann nicht rückgängig gemacht werden.",
|
||||
"Purge Data": "Alle Daten löschen",
|
||||
"Erase the book and all its data, including reading progress": "Buch und alle Daten löschen, einschließlich Lesefortschritt",
|
||||
"More Actions": "Weitere Aktionen",
|
||||
"Sign in and make the book available to share it": "Melde dich an und mache das Buch verfügbar, um es zu teilen",
|
||||
"Download the book to export it": "Lade das Buch herunter, um es zu exportieren",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "Bild konnte nicht gespeichert werden",
|
||||
"Share Image": "Bild teilen",
|
||||
"Save Image": "Bild speichern",
|
||||
"Image saved to gallery": "Bild in der Galerie gespeichert"
|
||||
"Image saved to gallery": "Bild in der Galerie gespeichert",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Bitte wählen Sie ein ganzes Wort aus oder deaktivieren Sie die Option „Ganzes Wort\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Ungültiger regulärer Ausdruck",
|
||||
"Find pattern cannot be empty": "Suchmuster darf nicht leer sein",
|
||||
"Add Rule": "Regel hinzufügen",
|
||||
"Find...": "Suchen…",
|
||||
"Replace with...": "Ersetzen durch…",
|
||||
"Purge & Delete": "Bereinigen und löschen",
|
||||
"Purge all reading data": "Alle Lesedaten bereinigen",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Dadurch werden Lesefortschritt, Notizen und Lesezeichen dauerhaft gelöscht. Dies kann nicht rückgängig gemacht werden.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Löscht auch Lesefortschritt, Notizen und Lesezeichen."
|
||||
}
|
||||
|
||||
@@ -448,6 +448,7 @@
|
||||
"TTS not supported for this document": "Η τεχνολογία TTS δεν υποστηρίζεται για αυτό το έγγραφο.",
|
||||
"Reset Password": "Επαναφορά κωδικού",
|
||||
"Show Reading Progress": "Εμφάνιση προόδου ανάγνωσης",
|
||||
"Show Progress Bar": "Εμφάνιση γραμμής προόδου",
|
||||
"Reading Progress Style": "Στυλ προόδου ανάγνωσης",
|
||||
"Page Number": "Αριθμός σελίδας",
|
||||
"Percentage": "Ποσοστό",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "Αυτόματος συγχρονισμός",
|
||||
"Purged book data: {{title}}": "Τα δεδομένα του βιβλίου διαγράφηκαν: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Αποτυχία διαγραφής δεδομένων βιβλίου: {{title}}",
|
||||
"Purge Book Data": "Διαγραφή δεδομένων βιβλίου",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Αυτό διαγράφει οριστικά το βιβλίο και όλα τα δεδομένα του, συμπεριλαμβανομένης της προόδου ανάγνωσης, των σημειώσεων και των σελιδοδεικτών. Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.",
|
||||
"Purge Data": "Διαγραφή όλων των δεδομένων",
|
||||
"Erase the book and all its data, including reading progress": "Διαγράφει το βιβλίο και όλα τα δεδομένα του, συμπεριλαμβανομένης της προόδου ανάγνωσης",
|
||||
"More Actions": "Περισσότερες ενέργειες",
|
||||
"Sign in and make the book available to share it": "Συνδεθείτε και κάντε το βιβλίο διαθέσιμο για να το μοιραστείτε",
|
||||
"Download the book to export it": "Κατεβάστε το βιβλίο για να το εξαγάγετε",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "Αποτυχία αποθήκευσης της εικόνας",
|
||||
"Share Image": "Κοινή χρήση εικόνας",
|
||||
"Save Image": "Αποθήκευση εικόνας",
|
||||
"Image saved to gallery": "Η εικόνα αποθηκεύτηκε στη συλλογή"
|
||||
"Image saved to gallery": "Η εικόνα αποθηκεύτηκε στη συλλογή",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Επιλέξτε μια ολόκληρη λέξη ή καταργήστε την επιλογή «Ολόκληρη λέξη».",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Μη έγκυρη κανονική έκφραση",
|
||||
"Find pattern cannot be empty": "Το μοτίβο αναζήτησης δεν μπορεί να είναι κενό",
|
||||
"Add Rule": "Προσθήκη κανόνα",
|
||||
"Find...": "Αναζήτηση…",
|
||||
"Replace with...": "Αντικατάσταση με…",
|
||||
"Purge & Delete": "Εκκαθάριση & Διαγραφή",
|
||||
"Purge all reading data": "Εκκαθάριση όλων των δεδομένων ανάγνωσης",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Αυτό διαγράφει οριστικά την πρόοδο ανάγνωσης, τις σημειώσεις και τους σελιδοδείκτες. Δεν είναι δυνατή η αναίρεση.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Διαγράφει επίσης την πρόοδο ανάγνωσης, τις σημειώσεις και τους σελιδοδείκτες."
|
||||
}
|
||||
|
||||
@@ -476,6 +476,7 @@
|
||||
"Reading Progress Style": "Estilo de progreso de lectura",
|
||||
"Percentage": "Porcentaje",
|
||||
"Show Reading Progress": "Mostrar progreso de lectura",
|
||||
"Show Progress Bar": "Mostrar barra de progreso",
|
||||
"Page Number": "Número de página",
|
||||
"Deleted local copy of the book: {{title}}": "Se eliminó la copia local del libro: {{title}}",
|
||||
"Failed to delete cloud backup of the book: {{title}}": "Error al eliminar la copia de seguridad en la nube del libro: {{title}}",
|
||||
@@ -1791,10 +1792,6 @@
|
||||
"Auto Sync": "Sincronización automática",
|
||||
"Purged book data: {{title}}": "Datos del libro borrados: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "No se pudieron borrar los datos del libro: {{title}}",
|
||||
"Purge Book Data": "Borrar todos los datos del libro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Esto borra permanentemente el libro y todos sus datos, incluido el progreso de lectura, las notas y los marcadores. Esta acción no se puede deshacer.",
|
||||
"Purge Data": "Borrar todos los datos",
|
||||
"Erase the book and all its data, including reading progress": "Borra el libro y todos sus datos, incluido el progreso de lectura",
|
||||
"More Actions": "Más acciones",
|
||||
"Sign in and make the book available to share it": "Inicia sesión y ten el libro disponible para compartirlo",
|
||||
"Download the book to export it": "Descarga el libro para exportarlo",
|
||||
@@ -1813,5 +1810,16 @@
|
||||
"Failed to save the image": "No se pudo guardar la imagen",
|
||||
"Share Image": "Compartir imagen",
|
||||
"Save Image": "Guardar imagen",
|
||||
"Image saved to gallery": "Imagen guardada en la galería"
|
||||
"Image saved to gallery": "Imagen guardada en la galería",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Selecciona una palabra completa o desmarca la opción «Palabra completa».",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Expresión regular no válida",
|
||||
"Find pattern cannot be empty": "El patrón de búsqueda no puede estar vacío",
|
||||
"Add Rule": "Añadir regla",
|
||||
"Find...": "Buscar…",
|
||||
"Replace with...": "Reemplazar por…",
|
||||
"Purge & Delete": "Purgar y eliminar",
|
||||
"Purge all reading data": "Purgar todos los datos de lectura",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Esto borra permanentemente el progreso de lectura, las notas y los marcadores. Esta acción no se puede deshacer.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "También borra el progreso de lectura, las notas y los marcadores."
|
||||
}
|
||||
|
||||
@@ -448,6 +448,7 @@
|
||||
"TTS not supported for this document": "قابلیت تبدیل متن به گفتار برای این سند پشتیبانی نمیشود",
|
||||
"Reset Password": "بازنشانی رمز عبور",
|
||||
"Show Reading Progress": "نمایش وضعیت مطالعه",
|
||||
"Show Progress Bar": "نمایش نوار پیشرفت",
|
||||
"Reading Progress Style": "سبک نمایش وضعیت مطالعه",
|
||||
"Page Number": "شماره صفحه",
|
||||
"Percentage": "درصد",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "همگامسازی خودکار",
|
||||
"Purged book data: {{title}}": "دادههای کتاب پاک شد: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "پاکسازی دادههای کتاب ناموفق بود: {{title}}",
|
||||
"Purge Book Data": "پاکسازی دادههای کتاب",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "این کار کتاب و تمام دادههای آن، شامل پیشرفت مطالعه، یادداشتها و نشانکها را برای همیشه پاک میکند. این عمل قابل بازگشت نیست.",
|
||||
"Purge Data": "پاکسازی دادهها",
|
||||
"Erase the book and all its data, including reading progress": "کتاب و تمام دادههای آن، شامل پیشرفت مطالعه را پاک میکند",
|
||||
"More Actions": "اقدامات بیشتر",
|
||||
"Sign in and make the book available to share it": "برای اشتراکگذاری، وارد شوید و کتاب را در دسترس قرار دهید",
|
||||
"Download the book to export it": "برای خروجی گرفتن، کتاب را دانلود کنید",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "ذخیره تصویر ناموفق بود",
|
||||
"Share Image": "اشتراکگذاری تصویر",
|
||||
"Save Image": "ذخیره تصویر",
|
||||
"Image saved to gallery": "تصویر در گالری ذخیره شد"
|
||||
"Image saved to gallery": "تصویر در گالری ذخیره شد",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "لطفاً یک کلمه کامل انتخاب کنید یا گزینه «کلمه کامل» را غیرفعال کنید.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "عبارت باقاعده نامعتبر است",
|
||||
"Find pattern cannot be empty": "الگوی جستجو نمیتواند خالی باشد",
|
||||
"Add Rule": "افزودن قاعده",
|
||||
"Find...": "جستجو…",
|
||||
"Replace with...": "جایگزین با…",
|
||||
"Purge & Delete": "پاکسازی و حذف",
|
||||
"Purge all reading data": "پاکسازی همه دادههای مطالعه",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "این کار وضعیت مطالعه، یادداشتها و نشانکها را برای همیشه پاک میکند. این عمل قابل بازگشت نیست.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "همچنین وضعیت مطالعه، یادداشتها و نشانکها را پاک میکند."
|
||||
}
|
||||
|
||||
@@ -452,6 +452,7 @@
|
||||
"TTS not supported for this document": "TTS non pris en charge pour ce document",
|
||||
"Reset Password": "Nouveau mot de passe",
|
||||
"Show Reading Progress": "Afficher la progression",
|
||||
"Show Progress Bar": "Afficher la barre de progression",
|
||||
"Reading Progress Style": "Style de progression",
|
||||
"Page Number": "Numéro de page",
|
||||
"Percentage": "Pourcentage",
|
||||
@@ -1791,10 +1792,6 @@
|
||||
"Auto Sync": "Synchronisation automatique",
|
||||
"Purged book data: {{title}}": "Données du livre purgées : {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Échec de la purge des données du livre : {{title}}",
|
||||
"Purge Book Data": "Purger les données du livre",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Cette action supprime définitivement le livre et toutes ses données, y compris la progression de lecture, les notes et les signets. Cette action est irréversible.",
|
||||
"Purge Data": "Purger les données",
|
||||
"Erase the book and all its data, including reading progress": "Supprime le livre et toutes ses données, y compris la progression de lecture",
|
||||
"More Actions": "Plus d'actions",
|
||||
"Sign in and make the book available to share it": "Connectez-vous et rendez le livre disponible pour le partager",
|
||||
"Download the book to export it": "Téléchargez le livre pour l'exporter",
|
||||
@@ -1813,5 +1810,16 @@
|
||||
"Failed to save the image": "Échec de l'enregistrement de l'image",
|
||||
"Share Image": "Partager l'image",
|
||||
"Save Image": "Enregistrer l'image",
|
||||
"Image saved to gallery": "Image enregistrée dans la galerie"
|
||||
"Image saved to gallery": "Image enregistrée dans la galerie",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Veuillez sélectionner un mot entier ou décocher l’option « Mot entier ».",
|
||||
"Regex:": "Regex :",
|
||||
"Invalid regular expression": "Expression régulière invalide",
|
||||
"Find pattern cannot be empty": "Le motif de recherche ne peut pas être vide",
|
||||
"Add Rule": "Ajouter une règle",
|
||||
"Find...": "Rechercher…",
|
||||
"Replace with...": "Remplacer par…",
|
||||
"Purge & Delete": "Purger et supprimer",
|
||||
"Purge all reading data": "Purger toutes les données de lecture",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Cela efface définitivement la progression de lecture, les notes et les signets. Cette action est irréversible.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Efface aussi la progression de lecture, les notes et les signets."
|
||||
}
|
||||
|
||||
@@ -950,6 +950,7 @@
|
||||
"Show Remaining Time": "הצג זמן נותר",
|
||||
"Show Remaining Pages": "הצג דפים נותרים",
|
||||
"Show Reading Progress": "הצג התקדמות קריאה",
|
||||
"Show Progress Bar": "הצג סרגל התקדמות",
|
||||
"Reading Progress Style": "סגנון התקדמות קריאה",
|
||||
"Page Number": "מספר דף",
|
||||
"Percentage": "אחוזים",
|
||||
@@ -1791,10 +1792,6 @@
|
||||
"Auto Sync": "סנכרון אוטומטי",
|
||||
"Purged book data: {{title}}": "נתוני הספר נמחקו: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "מחיקת נתוני הספר נכשלה: {{title}}",
|
||||
"Purge Book Data": "מחיקת כל נתוני הספר",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "פעולה זו מוחקת לצמיתות את הספר ואת כל הנתונים שלו, כולל התקדמות הקריאה, ההערות והסימניות. לא ניתן לבטל פעולה זו.",
|
||||
"Purge Data": "מחק את כל הנתונים",
|
||||
"Erase the book and all its data, including reading progress": "מחיקת הספר וכל הנתונים שלו, כולל התקדמות הקריאה",
|
||||
"More Actions": "פעולות נוספות",
|
||||
"Sign in and make the book available to share it": "היכנס והפוך את הספר לזמין כדי לשתף אותו",
|
||||
"Download the book to export it": "הורד את הספר כדי לייצא אותו",
|
||||
@@ -1813,5 +1810,16 @@
|
||||
"Failed to save the image": "שמירת התמונה נכשלה",
|
||||
"Share Image": "שיתוף התמונה",
|
||||
"Save Image": "שמירת התמונה",
|
||||
"Image saved to gallery": "התמונה נשמרה בגלריה"
|
||||
"Image saved to gallery": "התמונה נשמרה בגלריה",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "יש לבחור מילה שלמה או לבטל את האפשרות \"מילה שלמה\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "ביטוי רגולרי לא תקין",
|
||||
"Find pattern cannot be empty": "תבנית החיפוש לא יכולה להיות ריקה",
|
||||
"Add Rule": "הוסף כלל",
|
||||
"Find...": "חיפוש...",
|
||||
"Replace with...": "החלף ב...",
|
||||
"Purge & Delete": "נקה ומחק",
|
||||
"Purge all reading data": "נקה את כל נתוני הקריאה",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "פעולה זו מוחקת לצמיתות את התקדמות הקריאה, ההערות והסימניות. לא ניתן לבטל פעולה זו.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "מוחק גם את התקדמות הקריאה, ההערות והסימניות."
|
||||
}
|
||||
|
||||
@@ -448,6 +448,7 @@
|
||||
"TTS not supported for this document": "TTS इस दस्तावेज़ के लिए समर्थित नहीं है",
|
||||
"Reset Password": "पासवर्ड रीसेट करें",
|
||||
"Show Reading Progress": "पढ़ने की प्रगति दिखाएं",
|
||||
"Show Progress Bar": "प्रगति पट्टी दिखाएं",
|
||||
"Reading Progress Style": "पढ़ने की प्रगति शैली",
|
||||
"Page Number": "पृष्ठ संख्या",
|
||||
"Percentage": "प्रतिशत",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "स्वतः सिंक",
|
||||
"Purged book data: {{title}}": "पुस्तक का डेटा मिटाया गया: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "पुस्तक का डेटा मिटाने में विफल: {{title}}",
|
||||
"Purge Book Data": "पुस्तक का सारा डेटा मिटाएँ",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "इससे पुस्तक और उसका सारा डेटा, जिसमें पढ़ने की प्रगति, नोट्स और बुकमार्क शामिल हैं, स्थायी रूप से मिट जाएगा। इसे पूर्ववत नहीं किया जा सकता।",
|
||||
"Purge Data": "सारा डेटा मिटाएँ",
|
||||
"Erase the book and all its data, including reading progress": "पढ़ने की प्रगति सहित पुस्तक और उसका सारा डेटा मिटाएँ",
|
||||
"More Actions": "अधिक क्रियाएँ",
|
||||
"Sign in and make the book available to share it": "साझा करने के लिए साइन इन करें और पुस्तक उपलब्ध कराएँ",
|
||||
"Download the book to export it": "निर्यात करने के लिए पुस्तक डाउनलोड करें",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "छवि सहेजने में विफल",
|
||||
"Share Image": "छवि साझा करें",
|
||||
"Save Image": "छवि सहेजें",
|
||||
"Image saved to gallery": "छवि गैलरी में सहेजी गई"
|
||||
"Image saved to gallery": "छवि गैलरी में सहेजी गई",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "कृपया पूरा शब्द चुनें या \"पूरा शब्द\" विकल्प को अनचेक करें।",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "अमान्य रेगुलर एक्सप्रेशन",
|
||||
"Find pattern cannot be empty": "खोज पैटर्न खाली नहीं हो सकता",
|
||||
"Add Rule": "नियम जोड़ें",
|
||||
"Find...": "खोजें…",
|
||||
"Replace with...": "से बदलें…",
|
||||
"Purge & Delete": "साफ़ करें और हटाएं",
|
||||
"Purge all reading data": "सभी पढ़ने का डेटा साफ़ करें",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "यह पढ़ने की प्रगति, नोट्स और बुकमार्क को स्थायी रूप से मिटा देता है। इसे पूर्ववत नहीं किया जा सकता।",
|
||||
"Also erase reading progress, notes, and bookmarks.": "पढ़ने की प्रगति, नोट्स और बुकमार्क भी मिटा देता है।"
|
||||
}
|
||||
|
||||
@@ -1027,6 +1027,7 @@
|
||||
"Show Remaining Time": "Hátralévő idő megjelenítése",
|
||||
"Show Remaining Pages": "Hátralévő oldalak megjelenítése",
|
||||
"Show Reading Progress": "Olvasási haladás megjelenítése",
|
||||
"Show Progress Bar": "Folyamatjelző megjelenítése",
|
||||
"Reading Progress Style": "Olvasási haladás stílusa",
|
||||
"Percentage": "Százalék",
|
||||
"Show Current Time": "Aktuális idő megjelenítése",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "Automatikus szinkronizálás",
|
||||
"Purged book data: {{title}}": "Könyv adatai törölve: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "A könyv adatainak törlése sikertelen: {{title}}",
|
||||
"Purge Book Data": "Könyv összes adatának törlése",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Ez véglegesen törli a könyvet és minden adatát, beleértve az olvasási előrehaladást, a jegyzeteket és a könyvjelzőket. A művelet nem vonható vissza.",
|
||||
"Purge Data": "Összes adat törlése",
|
||||
"Erase the book and all its data, including reading progress": "Törli a könyvet és minden adatát, beleértve az olvasási előrehaladást",
|
||||
"More Actions": "További műveletek",
|
||||
"Sign in and make the book available to share it": "Jelentkezz be, és tedd elérhetővé a könyvet a megosztáshoz",
|
||||
"Download the book to export it": "Töltsd le a könyvet az exportáláshoz",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "Nem sikerült menteni a képet",
|
||||
"Share Image": "Kép megosztása",
|
||||
"Save Image": "Kép mentése",
|
||||
"Image saved to gallery": "A kép elmentve a galériába"
|
||||
"Image saved to gallery": "A kép elmentve a galériába",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Válasszon ki egy teljes szót, vagy törölje a „Teljes szó\" beállítás jelölését.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Érvénytelen reguláris kifejezés",
|
||||
"Find pattern cannot be empty": "A keresési minta nem lehet üres",
|
||||
"Add Rule": "Szabály hozzáadása",
|
||||
"Find...": "Keresés...",
|
||||
"Replace with...": "Csere erre...",
|
||||
"Purge & Delete": "Tisztítás és törlés",
|
||||
"Purge all reading data": "Összes olvasási adat törlése",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Ez véglegesen törli az olvasási haladást, a jegyzeteket és a könyvjelzőket. A művelet nem vonható vissza.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Az olvasási haladást, jegyzeteket és könyvjelzőket is törli."
|
||||
}
|
||||
|
||||
@@ -444,6 +444,7 @@
|
||||
"TTS not supported for this document": "TTS tidak didukung untuk dokumen ini",
|
||||
"Reset Password": "Reset Kata Sandi",
|
||||
"Show Reading Progress": "Perlihatkan Progres Membaca",
|
||||
"Show Progress Bar": "Tampilkan Bilah Progres",
|
||||
"Reading Progress Style": "Gaya Progres Membaca",
|
||||
"Page Number": "Nomor Halaman",
|
||||
"Percentage": "Persentase",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "Sinkronisasi Otomatis",
|
||||
"Purged book data: {{title}}": "Data buku dihapus: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Gagal menghapus data buku: {{title}}",
|
||||
"Purge Book Data": "Hapus semua data buku",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Ini akan menghapus buku secara permanen beserta semua datanya, termasuk progres baca, catatan, dan markah. Tindakan ini tidak dapat dibatalkan.",
|
||||
"Purge Data": "Hapus semua data",
|
||||
"Erase the book and all its data, including reading progress": "Menghapus buku dan semua datanya, termasuk progres baca",
|
||||
"More Actions": "Tindakan lainnya",
|
||||
"Sign in and make the book available to share it": "Masuk dan sediakan buku untuk membagikannya",
|
||||
"Download the book to export it": "Unduh buku untuk mengekspornya",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "Gagal menyimpan gambar",
|
||||
"Share Image": "Bagikan Gambar",
|
||||
"Save Image": "Simpan Gambar",
|
||||
"Image saved to gallery": "Gambar disimpan ke galeri"
|
||||
"Image saved to gallery": "Gambar disimpan ke galeri",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Pilih satu kata utuh atau hapus centang opsi \"Kata utuh\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Ekspresi reguler tidak valid",
|
||||
"Find pattern cannot be empty": "Pola pencarian tidak boleh kosong",
|
||||
"Add Rule": "Tambah aturan",
|
||||
"Find...": "Cari…",
|
||||
"Replace with...": "Ganti dengan…",
|
||||
"Purge & Delete": "Bersihkan & Hapus",
|
||||
"Purge all reading data": "Bersihkan semua data baca",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Ini menghapus permanen progres membaca, catatan, dan penanda. Tindakan ini tidak dapat dibatalkan.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Juga menghapus progres membaca, catatan, dan penanda."
|
||||
}
|
||||
|
||||
@@ -452,6 +452,7 @@
|
||||
"TTS not supported for this document": "TTS non supportato per questo documento",
|
||||
"Reset Password": "Reimposta Password",
|
||||
"Show Reading Progress": "Mostra Progresso Lettura",
|
||||
"Show Progress Bar": "Mostra barra di avanzamento",
|
||||
"Reading Progress Style": "Stile di Progresso Lettura",
|
||||
"Page Number": "Numero di Pagina",
|
||||
"Percentage": "Percentuale",
|
||||
@@ -1791,10 +1792,6 @@
|
||||
"Auto Sync": "Sincronizzazione automatica",
|
||||
"Purged book data: {{title}}": "Dati del libro eliminati: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Impossibile eliminare i dati del libro: {{title}}",
|
||||
"Purge Book Data": "Elimina tutti i dati del libro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Questa operazione elimina definitivamente il libro e tutti i suoi dati, inclusi i progressi di lettura, le note e i segnalibri. L'operazione non può essere annullata.",
|
||||
"Purge Data": "Elimina tutti i dati",
|
||||
"Erase the book and all its data, including reading progress": "Elimina il libro e tutti i suoi dati, inclusi i progressi di lettura",
|
||||
"More Actions": "Altre azioni",
|
||||
"Sign in and make the book available to share it": "Accedi e rendi disponibile il libro per condividerlo",
|
||||
"Download the book to export it": "Scarica il libro per esportarlo",
|
||||
@@ -1813,5 +1810,16 @@
|
||||
"Failed to save the image": "Impossibile salvare l'immagine",
|
||||
"Share Image": "Condividi immagine",
|
||||
"Save Image": "Salva immagine",
|
||||
"Image saved to gallery": "Immagine salvata nella galleria"
|
||||
"Image saved to gallery": "Immagine salvata nella galleria",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Seleziona una parola intera o deseleziona l’opzione «Parola intera».",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Espressione regolare non valida",
|
||||
"Find pattern cannot be empty": "Il criterio di ricerca non può essere vuoto",
|
||||
"Add Rule": "Aggiungi regola",
|
||||
"Find...": "Cerca…",
|
||||
"Replace with...": "Sostituisci con…",
|
||||
"Purge & Delete": "Svuota ed elimina",
|
||||
"Purge all reading data": "Elimina tutti i dati di lettura",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Questa operazione cancella definitivamente il progresso di lettura, le note e i segnalibri. Non può essere annullata.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Cancella anche il progresso di lettura, le note e i segnalibri."
|
||||
}
|
||||
|
||||
@@ -444,6 +444,7 @@
|
||||
"TTS not supported for this document": "TTSはこのドキュメントではサポートされていません",
|
||||
"Reset Password": "パスワードをリセット",
|
||||
"Show Reading Progress": "読書進捗を表示",
|
||||
"Show Progress Bar": "進捗バーを表示",
|
||||
"Reading Progress Style": "読書進捗スタイル",
|
||||
"Page Number": "ページ番号",
|
||||
"Percentage": "パーセンテージ",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "自動同期",
|
||||
"Purged book data: {{title}}": "書籍データを消去しました: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "書籍データの消去に失敗しました: {{title}}",
|
||||
"Purge Book Data": "書籍データを消去",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "これにより、本と読書の進行状況・メモ・しおりを含むすべてのデータが完全に削除されます。この操作は取り消せません。",
|
||||
"Purge Data": "データを消去",
|
||||
"Erase the book and all its data, including reading progress": "本と読書の進行状況を含むすべてのデータを消去します",
|
||||
"More Actions": "その他の操作",
|
||||
"Sign in and make the book available to share it": "共有するにはサインインして書籍を利用可能にしてください",
|
||||
"Download the book to export it": "エクスポートするには書籍をダウンロードしてください",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "画像の保存に失敗しました",
|
||||
"Share Image": "画像を共有",
|
||||
"Save Image": "画像を保存",
|
||||
"Image saved to gallery": "画像をギャラリーに保存しました"
|
||||
"Image saved to gallery": "画像をギャラリーに保存しました",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "単語全体を選択するか、「単語全体」オプションのチェックを外してください。",
|
||||
"Regex:": "正規表現:",
|
||||
"Invalid regular expression": "正規表現が無効です",
|
||||
"Find pattern cannot be empty": "検索パターンを空にできません",
|
||||
"Add Rule": "ルールを追加",
|
||||
"Find...": "検索…",
|
||||
"Replace with...": "置換後…",
|
||||
"Purge & Delete": "消去して削除",
|
||||
"Purge all reading data": "すべての読書データを消去",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "読書進捗、メモ、ブックマークが完全に消去されます。この操作は元に戻せません。",
|
||||
"Also erase reading progress, notes, and bookmarks.": "読書進捗、メモ、ブックマークも消去します。"
|
||||
}
|
||||
|
||||
@@ -444,6 +444,7 @@
|
||||
"TTS not supported for this document": "TTS가 이 문서에서 지원되지 않습니다",
|
||||
"Reset Password": "비밀번호 재설정",
|
||||
"Show Reading Progress": "읽기 진행 상황 표시",
|
||||
"Show Progress Bar": "진행률 표시줄 표시",
|
||||
"Reading Progress Style": "읽기 진행 상황 스타일",
|
||||
"Page Number": "페이지 번호",
|
||||
"Percentage": "백분율",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "자동 동기화",
|
||||
"Purged book data: {{title}}": "도서 데이터를 삭제했습니다: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "도서 데이터 삭제에 실패했습니다: {{title}}",
|
||||
"Purge Book Data": "도서 데이터 완전 삭제",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "책과 읽기 진행률, 메모, 책갈피를 포함한 모든 데이터가 영구적으로 삭제됩니다. 이 작업은 되돌릴 수 없습니다.",
|
||||
"Purge Data": "데이터 완전 삭제",
|
||||
"Erase the book and all its data, including reading progress": "읽기 진행률을 포함한 책과 모든 데이터를 삭제합니다",
|
||||
"More Actions": "추가 작업",
|
||||
"Sign in and make the book available to share it": "공유하려면 로그인하고 책을 사용할 수 있도록 하세요",
|
||||
"Download the book to export it": "내보내려면 책을 다운로드하세요",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "이미지를 저장하지 못했습니다",
|
||||
"Share Image": "이미지 공유",
|
||||
"Save Image": "이미지 저장",
|
||||
"Image saved to gallery": "이미지를 갤러리에 저장했습니다"
|
||||
"Image saved to gallery": "이미지를 갤러리에 저장했습니다",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "전체 단어를 선택하거나 '전체 단어' 옵션의 선택을 해제하세요.",
|
||||
"Regex:": "정규식:",
|
||||
"Invalid regular expression": "잘못된 정규식입니다",
|
||||
"Find pattern cannot be empty": "찾을 내용을 비워 둘 수 없습니다",
|
||||
"Add Rule": "규칙 추가",
|
||||
"Find...": "검색…",
|
||||
"Replace with...": "바꿀 내용…",
|
||||
"Purge & Delete": "데이터 지우고 삭제",
|
||||
"Purge all reading data": "모든 읽기 데이터 지우기",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "읽기 진행 상황, 메모, 북마크가 영구적으로 지워집니다. 이 작업은 되돌릴 수 없습니다.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "읽기 진행 상황, 메모, 북마크도 함께 지웁니다."
|
||||
}
|
||||
|
||||
@@ -594,6 +594,7 @@
|
||||
"Show Remaining Time": "Tunjuk Masa Berbaki",
|
||||
"Show Remaining Pages": "Tunjuk Halaman Berbaki",
|
||||
"Show Reading Progress": "Tunjuk Kemajuan Membaca",
|
||||
"Show Progress Bar": "Tunjuk Bar Kemajuan",
|
||||
"Reading Progress Style": "Gaya Kemajuan Membaca",
|
||||
"Page Number": "Nombor Halaman",
|
||||
"Percentage": "Peratusan",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "Segerak Automatik",
|
||||
"Purged book data: {{title}}": "Data buku dipadam: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Gagal memadam data buku: {{title}}",
|
||||
"Purge Book Data": "Padam semua data buku",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Ini memadamkan buku dan semua datanya secara kekal, termasuk kemajuan bacaan, nota dan penanda buku. Tindakan ini tidak boleh dibuat asal.",
|
||||
"Purge Data": "Padam semua data",
|
||||
"Erase the book and all its data, including reading progress": "Memadam buku dan semua datanya, termasuk kemajuan bacaan",
|
||||
"More Actions": "Tindakan lain",
|
||||
"Sign in and make the book available to share it": "Log masuk dan sediakan buku untuk berkongsinya",
|
||||
"Download the book to export it": "Muat turun buku untuk mengeksportnya",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "Gagal menyimpan imej",
|
||||
"Share Image": "Kongsi Imej",
|
||||
"Save Image": "Simpan Imej",
|
||||
"Image saved to gallery": "Imej disimpan ke galeri"
|
||||
"Image saved to gallery": "Imej disimpan ke galeri",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Sila pilih perkataan penuh atau nyahtanda pilihan \"Perkataan penuh\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Ungkapan biasa tidak sah",
|
||||
"Find pattern cannot be empty": "Corak carian tidak boleh kosong",
|
||||
"Add Rule": "Tambah peraturan",
|
||||
"Find...": "Cari…",
|
||||
"Replace with...": "Ganti dengan…",
|
||||
"Purge & Delete": "Bersihkan & Padam",
|
||||
"Purge all reading data": "Bersihkan semua data bacaan",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Ini memadam kemajuan membaca, nota dan penanda buku secara kekal. Tindakan ini tidak boleh dibatalkan.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Turut memadam kemajuan membaca, nota dan penanda buku."
|
||||
}
|
||||
|
||||
@@ -448,6 +448,7 @@
|
||||
"TTS not supported for this document": "TTS niet ondersteund voor dit document",
|
||||
"Reset Password": "Wachtwoord resetten",
|
||||
"Show Reading Progress": "Leesvoortgang weergeven",
|
||||
"Show Progress Bar": "Voortgangsbalk weergeven",
|
||||
"Reading Progress Style": "Stijl van leesvoortgang",
|
||||
"Page Number": "Pagina nummer",
|
||||
"Percentage": "Percentage",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "Automatische synchronisatie",
|
||||
"Purged book data: {{title}}": "Boekgegevens gewist: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Kan boekgegevens niet wissen: {{title}}",
|
||||
"Purge Book Data": "Alle boekgegevens wissen",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Hiermee worden het boek en alle bijbehorende gegevens, waaronder leesvoortgang, notities en bladwijzers, permanent gewist. Dit kan niet ongedaan worden gemaakt.",
|
||||
"Purge Data": "Alle gegevens wissen",
|
||||
"Erase the book and all its data, including reading progress": "Wist het boek en alle gegevens, inclusief leesvoortgang",
|
||||
"More Actions": "Meer acties",
|
||||
"Sign in and make the book available to share it": "Meld je aan en maak het boek beschikbaar om het te delen",
|
||||
"Download the book to export it": "Download het boek om het te exporteren",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "Kan de afbeelding niet opslaan",
|
||||
"Share Image": "Afbeelding delen",
|
||||
"Save Image": "Afbeelding opslaan",
|
||||
"Image saved to gallery": "Afbeelding opgeslagen in de galerij"
|
||||
"Image saved to gallery": "Afbeelding opgeslagen in de galerij",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Selecteer een heel woord of schakel de optie ‘Heel woord’ uit.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Ongeldige reguliere expressie",
|
||||
"Find pattern cannot be empty": "Zoekpatroon mag niet leeg zijn",
|
||||
"Add Rule": "Regel toevoegen",
|
||||
"Find...": "Zoeken…",
|
||||
"Replace with...": "Vervangen door…",
|
||||
"Purge & Delete": "Wissen en verwijderen",
|
||||
"Purge all reading data": "Alle leesgegevens wissen",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Hiermee worden leesvoortgang, notities en bladwijzers permanent gewist. Dit kan niet ongedaan worden gemaakt.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Wist ook leesvoortgang, notities en bladwijzers."
|
||||
}
|
||||
|
||||
@@ -456,6 +456,7 @@
|
||||
"TTS not supported for this document": "TTS nie jest obsługiwane dla tego dokumentu",
|
||||
"Reset Password": "Zresetuj hasło",
|
||||
"Show Reading Progress": "Pokazuj postęp czytania",
|
||||
"Show Progress Bar": "Pokaż pasek postępu",
|
||||
"Reading Progress Style": "Styl postępu czytania",
|
||||
"Page Number": "Numer strony",
|
||||
"Percentage": "Procent",
|
||||
@@ -1824,10 +1825,6 @@
|
||||
"Auto Sync": "Automatyczna synchronizacja",
|
||||
"Purged book data: {{title}}": "Usunięto dane książki: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Nie udało się usunąć danych książki: {{title}}",
|
||||
"Purge Book Data": "Usuń wszystkie dane książki",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Spowoduje to trwałe usunięcie książki i wszystkich jej danych, w tym postępu czytania, notatek i zakładek. Tej operacji nie można cofnąć.",
|
||||
"Purge Data": "Usuń wszystkie dane",
|
||||
"Erase the book and all its data, including reading progress": "Usuwa książkę i wszystkie jej dane, w tym postęp czytania",
|
||||
"More Actions": "Więcej akcji",
|
||||
"Sign in and make the book available to share it": "Zaloguj się i pobierz książkę, aby ją udostępnić",
|
||||
"Download the book to export it": "Pobierz książkę, aby ją wyeksportować",
|
||||
@@ -1846,5 +1843,16 @@
|
||||
"Failed to save the image": "Nie udało się zapisać obrazu",
|
||||
"Share Image": "Udostępnij obraz",
|
||||
"Save Image": "Zapisz obraz",
|
||||
"Image saved to gallery": "Obraz zapisano w galerii"
|
||||
"Image saved to gallery": "Obraz zapisano w galerii",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Zaznacz całe słowo lub odznacz opcję „Całe słowo\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Nieprawidłowe wyrażenie regularne",
|
||||
"Find pattern cannot be empty": "Wzorzec wyszukiwania nie może być pusty",
|
||||
"Add Rule": "Dodaj regułę",
|
||||
"Find...": "Szukaj…",
|
||||
"Replace with...": "Zastąp przez…",
|
||||
"Purge & Delete": "Wyczyść i usuń",
|
||||
"Purge all reading data": "Wyczyść wszystkie dane czytania",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Spowoduje to trwałe usunięcie postępu czytania, notatek i zakładek. Tej operacji nie można cofnąć.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Usuwa również postęp czytania, notatki i zakładki."
|
||||
}
|
||||
|
||||
@@ -1177,6 +1177,7 @@
|
||||
"Show Remaining Time": "Mostrar tempo restante",
|
||||
"Show Remaining Pages": "Mostrar páginas restantes",
|
||||
"Show Reading Progress": "Mostrar progresso de leitura",
|
||||
"Show Progress Bar": "Mostrar barra de progresso",
|
||||
"Reading Progress Style": "Estilo do progresso de leitura",
|
||||
"Percentage": "Porcentagem",
|
||||
"Show Current Time": "Mostrar hora atual",
|
||||
@@ -1791,10 +1792,6 @@
|
||||
"Auto Sync": "Sincronização automática",
|
||||
"Purged book data: {{title}}": "Dados do livro apagados: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Falha ao apagar os dados do livro: {{title}}",
|
||||
"Purge Book Data": "Apagar todos os dados do livro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Isso apaga permanentemente o livro e todos os seus dados, incluindo o progresso de leitura, notas e marcadores. Esta ação não pode ser desfeita.",
|
||||
"Purge Data": "Apagar todos os dados",
|
||||
"Erase the book and all its data, including reading progress": "Apaga o livro e todos os seus dados, incluindo o progresso de leitura",
|
||||
"More Actions": "Mais ações",
|
||||
"Sign in and make the book available to share it": "Faça login e tenha o livro disponível para compartilhá-lo",
|
||||
"Download the book to export it": "Baixe o livro para exportá-lo",
|
||||
@@ -1813,5 +1810,16 @@
|
||||
"Failed to save the image": "Falha ao salvar a imagem",
|
||||
"Share Image": "Compartilhar imagem",
|
||||
"Save Image": "Salvar imagem",
|
||||
"Image saved to gallery": "Imagem salva na galeria"
|
||||
"Image saved to gallery": "Imagem salva na galeria",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Selecione uma palavra inteira ou desmarque a opção \"Palavra inteira\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Expressão regular inválida",
|
||||
"Find pattern cannot be empty": "O padrão de busca não pode ficar vazio",
|
||||
"Add Rule": "Adicionar regra",
|
||||
"Find...": "Buscar...",
|
||||
"Replace with...": "Substituir por...",
|
||||
"Purge & Delete": "Limpar e excluir",
|
||||
"Purge all reading data": "Limpar todos os dados de leitura",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Isso apaga permanentemente o progresso de leitura, as notas e os marcadores. Esta ação não pode ser desfeita.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Também apaga o progresso de leitura, as notas e os marcadores."
|
||||
}
|
||||
|
||||
@@ -452,6 +452,7 @@
|
||||
"TTS not supported for this document": "TTS não suportado para este documento",
|
||||
"Reset Password": "Redefinir Senha",
|
||||
"Show Reading Progress": "Mostrar Progresso de Leitura",
|
||||
"Show Progress Bar": "Mostrar barra de progresso",
|
||||
"Reading Progress Style": "Estilo de Progresso de Leitura",
|
||||
"Page Number": "Número da Página",
|
||||
"Percentage": "Porcentagem",
|
||||
@@ -1791,10 +1792,6 @@
|
||||
"Auto Sync": "Sincronização Automática",
|
||||
"Purged book data: {{title}}": "Dados do livro apagados: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Falha ao apagar os dados do livro: {{title}}",
|
||||
"Purge Book Data": "Apagar todos os dados do livro",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Isto apaga permanentemente o livro e todos os seus dados, incluindo o progresso de leitura, notas e marcadores. Esta ação não pode ser desfeita.",
|
||||
"Purge Data": "Apagar todos os dados",
|
||||
"Erase the book and all its data, including reading progress": "Apaga o livro e todos os seus dados, incluindo o progresso de leitura",
|
||||
"More Actions": "Mais ações",
|
||||
"Sign in and make the book available to share it": "Inicie sessão e tenha o livro disponível para o partilhar",
|
||||
"Download the book to export it": "Transfira o livro para o exportar",
|
||||
@@ -1813,5 +1810,16 @@
|
||||
"Failed to save the image": "Falha ao salvar a imagem",
|
||||
"Share Image": "Partilhar imagem",
|
||||
"Save Image": "Salvar imagem",
|
||||
"Image saved to gallery": "Imagem guardada na galeria"
|
||||
"Image saved to gallery": "Imagem guardada na galeria",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Selecione uma palavra inteira ou desmarque a opção «Palavra inteira».",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Expressão regular inválida",
|
||||
"Find pattern cannot be empty": "O padrão de pesquisa não pode estar vazio",
|
||||
"Add Rule": "Adicionar regra",
|
||||
"Find...": "Buscar…",
|
||||
"Replace with...": "Substituir por…",
|
||||
"Purge & Delete": "Limpar e excluir",
|
||||
"Purge all reading data": "Limpar todos os dados de leitura",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Isto apaga permanentemente o progresso de leitura, notas e marcadores. Esta ação não pode ser desfeita.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Também apaga o progresso de leitura, notas e marcadores."
|
||||
}
|
||||
|
||||
@@ -1016,6 +1016,7 @@
|
||||
"Show Remaining Time": "Afișează timpul rămas",
|
||||
"Show Remaining Pages": "Afișează paginile rămase",
|
||||
"Show Reading Progress": "Afișează progresul citirii",
|
||||
"Show Progress Bar": "Afișează bara de progres",
|
||||
"Reading Progress Style": "Stilul progresului citirii",
|
||||
"Percentage": "Procent",
|
||||
"Show Current Time": "Afișează ora curentă",
|
||||
@@ -1791,10 +1792,6 @@
|
||||
"Auto Sync": "Sincronizare automată",
|
||||
"Purged book data: {{title}}": "Datele cărții au fost șterse: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Ștergerea datelor cărții a eșuat: {{title}}",
|
||||
"Purge Book Data": "Șterge toate datele cărții",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Aceasta șterge definitiv cartea și toate datele sale, inclusiv progresul lecturii, notițele și marcajele. Această acțiune nu poate fi anulată.",
|
||||
"Purge Data": "Șterge toate datele",
|
||||
"Erase the book and all its data, including reading progress": "Șterge cartea și toate datele sale, inclusiv progresul lecturii",
|
||||
"More Actions": "Mai multe acțiuni",
|
||||
"Sign in and make the book available to share it": "Conectează-te și fă cartea disponibilă pentru a o partaja",
|
||||
"Download the book to export it": "Descarcă cartea pentru a o exporta",
|
||||
@@ -1813,5 +1810,16 @@
|
||||
"Failed to save the image": "Salvarea imaginii a eșuat",
|
||||
"Share Image": "Partajează imaginea",
|
||||
"Save Image": "Salvează imaginea",
|
||||
"Image saved to gallery": "Imagine salvată în galerie"
|
||||
"Image saved to gallery": "Imagine salvată în galerie",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Selectați un cuvânt întreg sau debifați opțiunea „Cuvântul întreg\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Expresie regulată invalidă",
|
||||
"Find pattern cannot be empty": "Modelul de căutare nu poate fi gol",
|
||||
"Add Rule": "Adaugă regulă",
|
||||
"Find...": "Căutare...",
|
||||
"Replace with...": "Înlocuiește cu...",
|
||||
"Purge & Delete": "Curăță și șterge",
|
||||
"Purge all reading data": "Curăță toate datele de citire",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Aceasta șterge definitiv progresul citirii, notele și marcajele. Această acțiune nu poate fi anulată.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Șterge de asemenea progresul citirii, notele și marcajele."
|
||||
}
|
||||
|
||||
@@ -456,6 +456,7 @@
|
||||
"TTS not supported for this document": "TTS не поддерживается для этого документа",
|
||||
"Reset Password": "Сбросить пароль",
|
||||
"Show Reading Progress": "Показать прогресс чтения",
|
||||
"Show Progress Bar": "Показать полосу прогресса",
|
||||
"Reading Progress Style": "Стиль прогресса чтения",
|
||||
"Page Number": "Номер страницы",
|
||||
"Percentage": "Процент",
|
||||
@@ -1824,10 +1825,6 @@
|
||||
"Auto Sync": "Автосинхронизация",
|
||||
"Purged book data: {{title}}": "Данные книги очищены: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Не удалось очистить данные книги: {{title}}",
|
||||
"Purge Book Data": "Очистить данные книги",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Это навсегда удалит книгу и все её данные, включая прогресс чтения, заметки и закладки. Это действие нельзя отменить.",
|
||||
"Purge Data": "Очистить данные",
|
||||
"Erase the book and all its data, including reading progress": "Удаляет книгу и все её данные, включая прогресс чтения",
|
||||
"More Actions": "Ещё действия",
|
||||
"Sign in and make the book available to share it": "Войдите и сделайте книгу доступной, чтобы поделиться ею",
|
||||
"Download the book to export it": "Скачайте книгу, чтобы экспортировать её",
|
||||
@@ -1846,5 +1843,16 @@
|
||||
"Failed to save the image": "Не удалось сохранить изображение",
|
||||
"Share Image": "Поделиться изображением",
|
||||
"Save Image": "Сохранить изображение",
|
||||
"Image saved to gallery": "Изображение сохранено в галерее"
|
||||
"Image saved to gallery": "Изображение сохранено в галерее",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Выберите слово целиком или снимите флажок «Слово целиком».",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Недопустимое регулярное выражение",
|
||||
"Find pattern cannot be empty": "Шаблон поиска не может быть пустым",
|
||||
"Add Rule": "Добавить правило",
|
||||
"Find...": "Поиск…",
|
||||
"Replace with...": "Заменить на…",
|
||||
"Purge & Delete": "Очистить и удалить",
|
||||
"Purge all reading data": "Очистить все данные чтения",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Это безвозвратно удалит прогресс чтения, заметки и закладки. Это действие нельзя отменить.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Также удаляет прогресс чтения, заметки и закладки."
|
||||
}
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
"Show Remaining Time": "ඉතිරි වේලාව පෙන්වන්න",
|
||||
"Show Remaining Pages": "ඉතිරි පිටු පෙන්වන්න",
|
||||
"Show Reading Progress": "කියවීමේ ප්රගතිය පෙන්වන්න",
|
||||
"Show Progress Bar": "ප්රගති තීරුව පෙන්වන්න",
|
||||
"Reading Progress Style": "කියවීමේ ප්රගති ශෛලිය",
|
||||
"Page Number": "පිටු අංකය",
|
||||
"Percentage": "ප්රතිශතය",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "ස්වයංක්රීය සමමුහුර්තය",
|
||||
"Purged book data: {{title}}": "පොතේ දත්ත මකා දමන ලදී: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "පොතේ දත්ත මැකීමට අසමත් විය: {{title}}",
|
||||
"Purge Book Data": "පොතේ සියලු දත්ත මකන්න",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "මෙය පොත සහ කියවීමේ ප්රගතිය, සටහන් සහ පිටු සලකුණු ඇතුළුව එහි සියලු දත්ත ස්ථිරවම මකා දමයි. මෙය පෙරළිය නොහැක.",
|
||||
"Purge Data": "සියලු දත්ත මකන්න",
|
||||
"Erase the book and all its data, including reading progress": "කියවීමේ ප්රගතිය ඇතුළුව පොත සහ එහි සියලු දත්ත මකන්න",
|
||||
"More Actions": "තවත් ක්රියා",
|
||||
"Sign in and make the book available to share it": "බෙදා ගැනීමට පුරනය වී පොත ලබා ගත හැකි කරන්න",
|
||||
"Download the book to export it": "අපනයනය කිරීමට පොත බාගන්න",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "රූපය සුරැකීමට අසමත් විය",
|
||||
"Share Image": "රූපය බෙදාගන්න",
|
||||
"Save Image": "රූපය සුරකින්න",
|
||||
"Image saved to gallery": "රූපය ගැලරියට සුරැකිණි"
|
||||
"Image saved to gallery": "රූපය ගැලරියට සුරැකිණි",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "සම්පූර්ණ වචනයක් තෝරන්න හෝ \"සම්පූර්ණ වචනය\" විකල්පය ඉවත් කරන්න.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "වලංගු නොවන නිත්ය ප්රකාශනය",
|
||||
"Find pattern cannot be empty": "සෙවුම් රටාව හිස් විය නොහැක",
|
||||
"Add Rule": "රීතිය එක් කරන්න",
|
||||
"Find...": "සොයන්න…",
|
||||
"Replace with...": "ප්රතිස්ථාපනය කරන්න…",
|
||||
"Purge & Delete": "ඉවත් කර මකන්න",
|
||||
"Purge all reading data": "සියලු කියවීම් දත්ත ඉවත් කරන්න",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "මෙය කියවීමේ ප්රගතිය, සටහන් සහ පොත් සලකුණු ස්ථිරවම මකා දමයි. මෙය අහෝසි කළ නොහැක.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "කියවීමේ ප්රගතිය, සටහන් සහ පොත් සලකුණු ද මකා දමයි."
|
||||
}
|
||||
|
||||
@@ -991,6 +991,7 @@
|
||||
"Show Remaining Time": "Priki preostali čas",
|
||||
"Show Remaining Pages": "Prikaži preostale strani",
|
||||
"Show Reading Progress": "Prikaži napredek branja",
|
||||
"Show Progress Bar": "Prikaži vrstico napredka",
|
||||
"Reading Progress Style": "Slog napredka branja",
|
||||
"Percentage": "Odstotek",
|
||||
"Tap to Toggle Footer": "Tapnite za preklop noge",
|
||||
@@ -1824,10 +1825,6 @@
|
||||
"Auto Sync": "Samodejna sinhronizacija",
|
||||
"Purged book data: {{title}}": "Podatki knjige izbrisani: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Podatkov knjige ni bilo mogoče izbrisati: {{title}}",
|
||||
"Purge Book Data": "Izbriši vse podatke knjige",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "S tem trajno izbrišete knjigo in vse njene podatke, vključno z napredkom branja, zapiski in zaznamki. Tega dejanja ni mogoče razveljaviti.",
|
||||
"Purge Data": "Izbriši vse podatke",
|
||||
"Erase the book and all its data, including reading progress": "Izbriše knjigo in vse njene podatke, vključno z napredkom branja",
|
||||
"More Actions": "Več dejanj",
|
||||
"Sign in and make the book available to share it": "Prijavite se in omogočite knjigo za deljenje",
|
||||
"Download the book to export it": "Prenesite knjigo, da jo izvozite",
|
||||
@@ -1846,5 +1843,16 @@
|
||||
"Failed to save the image": "Slike ni bilo mogoče shraniti",
|
||||
"Share Image": "Deli sliko",
|
||||
"Save Image": "Shrani sliko",
|
||||
"Image saved to gallery": "Slika je shranjena v galerijo"
|
||||
"Image saved to gallery": "Slika je shranjena v galerijo",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Izberite celo besedo ali počistite možnost »Cela beseda«.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Neveljaven regularni izraz",
|
||||
"Find pattern cannot be empty": "Iskalni vzorec ne sme biti prazen",
|
||||
"Add Rule": "Dodaj pravilo",
|
||||
"Find...": "Iskanje...",
|
||||
"Replace with...": "Zamenjaj z...",
|
||||
"Purge & Delete": "Počisti in izbriši",
|
||||
"Purge all reading data": "Počisti vse podatke o branju",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "To trajno izbriše napredek branja, opombe in zaznamke. Tega ni mogoče razveljaviti.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Izbriše tudi napredek branja, opombe in zaznamke."
|
||||
}
|
||||
|
||||
@@ -509,6 +509,7 @@
|
||||
"Show Remaining Time": "Visa återstående tid",
|
||||
"Show Remaining Pages": "Visa återstående sidor",
|
||||
"Show Reading Progress": "Visa läsframsteg",
|
||||
"Show Progress Bar": "Visa förloppsindikator",
|
||||
"Reading Progress Style": "Läsframstegsstil",
|
||||
"Page Number": "Sidnummer",
|
||||
"Percentage": "Procent",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "Automatisk synkronisering",
|
||||
"Purged book data: {{title}}": "Bokdata rensad: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Det gick inte att rensa bokdata: {{title}}",
|
||||
"Purge Book Data": "Rensa all bokdata",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Detta raderar permanent boken och all dess data, inklusive läsförlopp, anteckningar och bokmärken. Detta kan inte ångras.",
|
||||
"Purge Data": "Rensa all data",
|
||||
"Erase the book and all its data, including reading progress": "Raderar boken och all data, inklusive läsförlopp",
|
||||
"More Actions": "Fler åtgärder",
|
||||
"Sign in and make the book available to share it": "Logga in och gör boken tillgänglig för att dela den",
|
||||
"Download the book to export it": "Ladda ner boken för att exportera den",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "Det gick inte att spara bilden",
|
||||
"Share Image": "Dela bild",
|
||||
"Save Image": "Spara bild",
|
||||
"Image saved to gallery": "Bilden har sparats i galleriet"
|
||||
"Image saved to gallery": "Bilden har sparats i galleriet",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Markera ett helt ord eller avmarkera alternativet ”Hela ordet”.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Ogiltigt reguljärt uttryck",
|
||||
"Find pattern cannot be empty": "Sökmönstret får inte vara tomt",
|
||||
"Add Rule": "Lägg till regel",
|
||||
"Find...": "Sök…",
|
||||
"Replace with...": "Ersätt med…",
|
||||
"Purge & Delete": "Rensa och ta bort",
|
||||
"Purge all reading data": "Rensa alla läsdata",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Detta raderar permanent läsframsteg, anteckningar och bokmärken. Detta kan inte ångras.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Raderar även läsframsteg, anteckningar och bokmärken."
|
||||
}
|
||||
|
||||
@@ -267,6 +267,7 @@
|
||||
"Show Remaining Time": "மீதமுள்ள நேரத்தைக் காட்டவும்",
|
||||
"Show Remaining Pages": "மீதமுள்ள பக்கங்களைக் காட்டவும்",
|
||||
"Show Reading Progress": "வாசிப்பு முன்னேற்றத்தைக் காட்டவும்",
|
||||
"Show Progress Bar": "முன்னேற்றப் பட்டியைக் காட்டவும்",
|
||||
"Reading Progress Style": "வாசிப்பு முன்னேற்ற பாணி",
|
||||
"Page Number": "பக்க எண்",
|
||||
"Percentage": "சதவீதம்",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "தானியங்கு ஒத்திசைவு",
|
||||
"Purged book data: {{title}}": "புத்தகத் தரவு அழிக்கப்பட்டது: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "புத்தகத் தரவை அழிக்க முடியவில்லை: {{title}}",
|
||||
"Purge Book Data": "புத்தகத்தின் எல்லா தரவையும் அழி",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "இது புத்தகத்தையும் வாசிப்பு முன்னேற்றம், குறிப்புகள் மற்றும் புத்தகக்குறிகள் உள்ளிட்ட அதன் அனைத்து தரவையும் நிரந்தரமாக அழிக்கும். இதை மீட்டெடுக்க முடியாது.",
|
||||
"Purge Data": "எல்லா தரவையும் அழி",
|
||||
"Erase the book and all its data, including reading progress": "வாசிப்பு முன்னேற்றம் உட்பட புத்தகத்தையும் அதன் எல்லா தரவையும் அழிக்கும்",
|
||||
"More Actions": "மேலும் செயல்கள்",
|
||||
"Sign in and make the book available to share it": "பகிர உள்நுழைந்து புத்தகத்தைக் கிடைக்கச் செய்யவும்",
|
||||
"Download the book to export it": "ஏற்றுமதி செய்ய புத்தகத்தைப் பதிவிறக்கவும்",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "படத்தைச் சேமிக்க முடியவில்லை",
|
||||
"Share Image": "படத்தைப் பகிர்",
|
||||
"Save Image": "படத்தைச் சேமி",
|
||||
"Image saved to gallery": "படம் கேலரியில் சேமிக்கப்பட்டது"
|
||||
"Image saved to gallery": "படம் கேலரியில் சேமிக்கப்பட்டது",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "முழுச் சொல்லைத் தேர்ந்தெடுக்கவும் அல்லது \"முழு சொல்\" விருப்பத்தை நீக்கவும்.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "தவறான வழக்கமான வெளிப்பாடு",
|
||||
"Find pattern cannot be empty": "தேடல் வடிவத்தை வெறுமையாக வைக்க முடியாது",
|
||||
"Add Rule": "விதியைச் சேர்க்கவும்",
|
||||
"Find...": "தேடவும்…",
|
||||
"Replace with...": "மாற்றவும்…",
|
||||
"Purge & Delete": "அழித்து நீக்கு",
|
||||
"Purge all reading data": "அனைத்து வாசிப்புத் தரவையும் அழி",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "இது வாசிப்பு முன்னேற்றம், குறிப்புகள் மற்றும் புக்மார்க்குகளை நிரந்தரமாக அழிக்கும். இதை மீட்டெடுக்க முடியாது.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "வாசிப்பு முன்னேற்றம், குறிப்புகள் மற்றும் புக்மார்க்குகளையும் அழிக்கும்."
|
||||
}
|
||||
|
||||
@@ -444,6 +444,7 @@
|
||||
"TTS not supported for this document": "ไม่รองรับ TTS สำหรับเอกสารนี้",
|
||||
"Reset Password": "รีเซ็ตพาสเวิร์ด",
|
||||
"Show Reading Progress": "แสดงความคืบหน้าในการอ่าน",
|
||||
"Show Progress Bar": "แสดงแถบความคืบหน้า",
|
||||
"Reading Progress Style": "สไตล์ความก้าวหน้าในการอ่าน",
|
||||
"Page Number": "หมายเลขหน้า",
|
||||
"Percentage": "เปอร์เซ็นต์",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "ซิงค์อัตโนมัติ",
|
||||
"Purged book data: {{title}}": "ล้างข้อมูลหนังสือแล้ว: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "ล้างข้อมูลหนังสือไม่สำเร็จ: {{title}}",
|
||||
"Purge Book Data": "ล้างข้อมูลหนังสือทั้งหมด",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "การดำเนินการนี้จะลบหนังสือและข้อมูลทั้งหมดอย่างถาวร รวมถึงความคืบหน้าการอ่าน บันทึก และที่คั่นหนังสือ ไม่สามารถเลิกทำได้",
|
||||
"Purge Data": "ล้างข้อมูลทั้งหมด",
|
||||
"Erase the book and all its data, including reading progress": "ลบหนังสือและข้อมูลทั้งหมด รวมถึงความคืบหน้าการอ่าน",
|
||||
"More Actions": "การทำงานเพิ่มเติม",
|
||||
"Sign in and make the book available to share it": "ลงชื่อเข้าใช้และทำให้หนังสือพร้อมใช้งานเพื่อแชร์",
|
||||
"Download the book to export it": "ดาวน์โหลดหนังสือเพื่อส่งออก",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "ไม่สามารถบันทึกรูปภาพได้",
|
||||
"Share Image": "แชร์รูปภาพ",
|
||||
"Save Image": "บันทึกรูปภาพ",
|
||||
"Image saved to gallery": "บันทึกรูปภาพไปยังแกลเลอรีแล้ว"
|
||||
"Image saved to gallery": "บันทึกรูปภาพไปยังแกลเลอรีแล้ว",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "โปรดเลือกทั้งคำ หรือยกเลิกการเลือกตัวเลือก \"คำทั้งคำ\"",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "นิพจน์ทั่วไปไม่ถูกต้อง",
|
||||
"Find pattern cannot be empty": "รูปแบบการค้นหาต้องไม่ว่างเปล่า",
|
||||
"Add Rule": "เพิ่มกฎ",
|
||||
"Find...": "ค้นหา…",
|
||||
"Replace with...": "แทนที่ด้วย…",
|
||||
"Purge & Delete": "ล้างและลบ",
|
||||
"Purge all reading data": "ล้างข้อมูลการอ่านทั้งหมด",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "การดำเนินการนี้จะลบความคืบหน้าในการอ่าน บันทึก และบุ๊กมาร์กอย่างถาวร ไม่สามารถเลิกทำได้",
|
||||
"Also erase reading progress, notes, and bookmarks.": "ลบความคืบหน้าในการอ่าน บันทึก และบุ๊กมาร์กด้วย"
|
||||
}
|
||||
|
||||
@@ -448,6 +448,7 @@
|
||||
"TTS not supported for this document": "TTS bu belge için desteklenmiyor",
|
||||
"Reset Password": "Şifreyi Sıfırla",
|
||||
"Show Reading Progress": "Okuma İlerlemesini Göster",
|
||||
"Show Progress Bar": "İlerleme Çubuğunu Göster",
|
||||
"Reading Progress Style": "Okuma İlerlemesi Stili",
|
||||
"Page Number": "Sayfa Numarası",
|
||||
"Percentage": "Yüzde",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "Otomatik Senkronizasyon",
|
||||
"Purged book data: {{title}}": "Kitap verileri silindi: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Kitap verileri silinemedi: {{title}}",
|
||||
"Purge Book Data": "Tüm kitap verilerini sil",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Bu işlem kitabı ve okuma ilerlemesi, notlar ve yer imleri dahil tüm verilerini kalıcı olarak siler. Bu işlem geri alınamaz.",
|
||||
"Purge Data": "Tüm verileri sil",
|
||||
"Erase the book and all its data, including reading progress": "Kitabı ve okuma ilerlemesi dahil tüm verilerini siler",
|
||||
"More Actions": "Diğer eylemler",
|
||||
"Sign in and make the book available to share it": "Paylaşmak için oturum açın ve kitabı kullanılabilir hale getirin",
|
||||
"Download the book to export it": "Dışa aktarmak için kitabı indirin",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "Görsel kaydedilemedi",
|
||||
"Share Image": "Görseli Paylaş",
|
||||
"Save Image": "Görseli Kaydet",
|
||||
"Image saved to gallery": "Görsel galeriye kaydedildi"
|
||||
"Image saved to gallery": "Görsel galeriye kaydedildi",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Lütfen tam bir kelime seçin veya \"Tam kelime\" seçeneğinin işaretini kaldırın.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Geçersiz düzenli ifade",
|
||||
"Find pattern cannot be empty": "Arama deseni boş olamaz",
|
||||
"Add Rule": "Kural ekle",
|
||||
"Find...": "Ara…",
|
||||
"Replace with...": "Şununla değiştir…",
|
||||
"Purge & Delete": "Temizle ve sil",
|
||||
"Purge all reading data": "Tüm okuma verilerini temizle",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Bu, okuma ilerlemesini, notları ve yer işaretlerini kalıcı olarak siler. Bu işlem geri alınamaz.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Okuma ilerlemesi, notlar ve yer işaretlerini de siler."
|
||||
}
|
||||
|
||||
@@ -456,6 +456,7 @@
|
||||
"TTS not supported for this document": "TTS не підтримується в цьому документі",
|
||||
"Reset Password": "Скинути пароль",
|
||||
"Show Reading Progress": "Показати проґрес читання",
|
||||
"Show Progress Bar": "Показати смугу прогресу",
|
||||
"Reading Progress Style": "Стиль проґресу читання",
|
||||
"Page Number": "Номер сторінки",
|
||||
"Percentage": "Відсотки",
|
||||
@@ -1824,10 +1825,6 @@
|
||||
"Auto Sync": "Автоматична синхронізація",
|
||||
"Purged book data: {{title}}": "Дані книги очищено: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Не вдалося очистити дані книги: {{title}}",
|
||||
"Purge Book Data": "Очистити дані книги",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Це назавжди видалить книгу та всі її дані, зокрема прогрес читання, нотатки та закладки. Цю дію неможливо скасувати.",
|
||||
"Purge Data": "Очистити дані",
|
||||
"Erase the book and all its data, including reading progress": "Видаляє книгу та всі її дані, зокрема прогрес читання",
|
||||
"More Actions": "Більше дій",
|
||||
"Sign in and make the book available to share it": "Увійдіть і зробіть книгу доступною, щоб поділитися нею",
|
||||
"Download the book to export it": "Завантажте книгу, щоб експортувати її",
|
||||
@@ -1846,5 +1843,16 @@
|
||||
"Failed to save the image": "Не вдалося зберегти зображення",
|
||||
"Share Image": "Поділитися зображенням",
|
||||
"Save Image": "Зберегти зображення",
|
||||
"Image saved to gallery": "Зображення збережено в галереї"
|
||||
"Image saved to gallery": "Зображення збережено в галереї",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Виберіть ціле слово або зніміть прапорець «Ціле слово».",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Недійсний регулярний вираз",
|
||||
"Find pattern cannot be empty": "Шаблон пошуку не може бути порожнім",
|
||||
"Add Rule": "Додати правило",
|
||||
"Find...": "Пошук…",
|
||||
"Replace with...": "Замінити на…",
|
||||
"Purge & Delete": "Очистити та видалити",
|
||||
"Purge all reading data": "Очистити всі дані читання",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Це назавжди видалить проґрес читання, нотатки та закладки. Цю дію не можна скасувати.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Також видаляє проґрес читання, нотатки та закладки."
|
||||
}
|
||||
|
||||
@@ -1155,6 +1155,7 @@
|
||||
"Show Remaining Time": "Qolgan vaqtni koʻrsatish",
|
||||
"Show Remaining Pages": "Qolgan sahifalarni koʻrsatish",
|
||||
"Show Reading Progress": "Oʻqish jarayonini koʻrsatish",
|
||||
"Show Progress Bar": "Jarayon panelini koʻrsatish",
|
||||
"Reading Progress Style": "Oʻqish jarayoni uslubi",
|
||||
"Percentage": "Foiz",
|
||||
"Show Current Time": "Joriy vaqtni koʻrsatish",
|
||||
@@ -1758,10 +1759,6 @@
|
||||
"Auto Sync": "Avtomatik sinxronlash",
|
||||
"Purged book data: {{title}}": "Kitob maʼlumotlari oʻchirildi: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Kitob maʼlumotlarini oʻchirib boʻlmadi: {{title}}",
|
||||
"Purge Book Data": "Kitobning barcha maʼlumotlarini oʻchirish",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Bu kitobni va uning barcha maʼlumotlarini, jumladan oʻqish jarayoni, eslatmalar va xatcho‘plarni butunlay oʻchiradi. Buni qaytarib boʻlmaydi.",
|
||||
"Purge Data": "Barcha maʼlumotlarni oʻchirish",
|
||||
"Erase the book and all its data, including reading progress": "Kitobni va uning barcha maʼlumotlarini, jumladan oʻqish jarayonini oʻchiradi",
|
||||
"More Actions": "Qoʻshimcha amallar",
|
||||
"Sign in and make the book available to share it": "Ulashish uchun tizimga kiring va kitobni mavjud qiling",
|
||||
"Download the book to export it": "Eksport qilish uchun kitobni yuklab oling",
|
||||
@@ -1780,5 +1777,16 @@
|
||||
"Failed to save the image": "Rasmni saqlab bo'lmadi",
|
||||
"Share Image": "Rasmni ulashish",
|
||||
"Save Image": "Rasmni saqlash",
|
||||
"Image saved to gallery": "Rasm galereyaga saqlandi"
|
||||
"Image saved to gallery": "Rasm galereyaga saqlandi",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Butun soʻzni tanlang yoki \"Butun soʻz\" amalini olib tashlang.",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Yaroqsiz muntazam ifoda",
|
||||
"Find pattern cannot be empty": "Qidiruv namunasi boʻsh boʻlishi mumkin emas",
|
||||
"Add Rule": "Qoida qoʻshish",
|
||||
"Find...": "Qidirish...",
|
||||
"Replace with...": "Bilan almashtirish...",
|
||||
"Purge & Delete": "Tozalash va oʻchirish",
|
||||
"Purge all reading data": "Barcha oʻqish maʼlumotlarini tozalash",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Bu oʻqish jarayoni, eslatmalar va xatchoʻplarni butunlay oʻchiradi. Buni qaytarib boʻlmaydi.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Shuningdek, oʻqish jarayoni, eslatmalar va xatchoʻplarni ham oʻchiradi."
|
||||
}
|
||||
|
||||
@@ -444,6 +444,7 @@
|
||||
"TTS not supported for this document": "TTS không được hỗ trợ cho tài liệu này",
|
||||
"Reset Password": "Đặt lại mật khẩu",
|
||||
"Show Reading Progress": "Hiển thị tiến độ đọc",
|
||||
"Show Progress Bar": "Hiển thị thanh tiến độ",
|
||||
"Reading Progress Style": "Phong cách tiến độ đọc",
|
||||
"Page Number": "Số trang",
|
||||
"Percentage": "Phần trăm",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "Tự động đồng bộ",
|
||||
"Purged book data: {{title}}": "Đã xóa dữ liệu sách: {{title}}",
|
||||
"Failed to purge book data: {{title}}": "Không thể xóa dữ liệu sách: {{title}}",
|
||||
"Purge Book Data": "Xóa toàn bộ dữ liệu sách",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "Thao tác này sẽ xóa vĩnh viễn sách và toàn bộ dữ liệu của nó, bao gồm tiến độ đọc, ghi chú và dấu trang. Không thể hoàn tác.",
|
||||
"Purge Data": "Xóa toàn bộ dữ liệu",
|
||||
"Erase the book and all its data, including reading progress": "Xóa sách và toàn bộ dữ liệu, bao gồm tiến độ đọc",
|
||||
"More Actions": "Thao tác khác",
|
||||
"Sign in and make the book available to share it": "Đăng nhập và tải sách về để chia sẻ",
|
||||
"Download the book to export it": "Tải sách về để xuất ra",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "Không thể lưu hình ảnh",
|
||||
"Share Image": "Chia sẻ hình ảnh",
|
||||
"Save Image": "Lưu hình ảnh",
|
||||
"Image saved to gallery": "Đã lưu hình ảnh vào thư viện"
|
||||
"Image saved to gallery": "Đã lưu hình ảnh vào thư viện",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "Vui lòng chọn một từ hoàn chỉnh hoặc bỏ chọn tùy chọn \"Toàn bộ từ\".",
|
||||
"Regex:": "Regex:",
|
||||
"Invalid regular expression": "Biểu thức chính quy không hợp lệ",
|
||||
"Find pattern cannot be empty": "Mẫu tìm kiếm không được để trống",
|
||||
"Add Rule": "Thêm quy tắc",
|
||||
"Find...": "Tìm kiếm…",
|
||||
"Replace with...": "Thay thế bằng…",
|
||||
"Purge & Delete": "Dọn sạch và xóa",
|
||||
"Purge all reading data": "Xóa toàn bộ dữ liệu đọc",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Thao tác này xóa vĩnh viễn tiến độ đọc, ghi chú và dấu trang. Không thể hoàn tác.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Đồng thời xóa tiến độ đọc, ghi chú và dấu trang."
|
||||
}
|
||||
|
||||
@@ -445,6 +445,7 @@
|
||||
"TTS not supported for this document": "TTS 不支持此文档",
|
||||
"Reset Password": "重置密码",
|
||||
"Show Reading Progress": "显示阅读进度",
|
||||
"Show Progress Bar": "显示进度条",
|
||||
"Reading Progress Style": "阅读进度样式",
|
||||
"Page Number": "页码",
|
||||
"Percentage": "百分比",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "自动同步",
|
||||
"Purged book data: {{title}}": "已清除书籍数据:{{title}}",
|
||||
"Failed to purge book data: {{title}}": "清除书籍数据失败:{{title}}",
|
||||
"Purge Book Data": "清除书籍数据",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "这将永久删除该书籍及其所有数据,包括阅读进度、笔记和书签。此操作无法撤销。",
|
||||
"Purge Data": "清除数据",
|
||||
"Erase the book and all its data, including reading progress": "删除该书籍及其所有数据,包括阅读进度",
|
||||
"More Actions": "更多操作",
|
||||
"Sign in and make the book available to share it": "登录并使书籍可用后即可分享",
|
||||
"Download the book to export it": "下载书籍后即可导出",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "图片保存失败",
|
||||
"Share Image": "分享图片",
|
||||
"Save Image": "保存图片",
|
||||
"Image saved to gallery": "图片已保存到相册"
|
||||
"Image saved to gallery": "图片已保存到相册",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "请选择完整的单词,或取消勾选\"全词匹配\"选项。",
|
||||
"Regex:": "正则:",
|
||||
"Invalid regular expression": "正则表达式无效",
|
||||
"Find pattern cannot be empty": "查找内容不能为空",
|
||||
"Add Rule": "添加规则",
|
||||
"Find...": "查找…",
|
||||
"Replace with...": "替换为…",
|
||||
"Purge & Delete": "清除并删除",
|
||||
"Purge all reading data": "清除所有阅读数据",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "这将永久清除阅读进度、笔记和书签,且无法撤销。",
|
||||
"Also erase reading progress, notes, and bookmarks.": "同时清除阅读进度、笔记和书签。"
|
||||
}
|
||||
|
||||
@@ -444,6 +444,7 @@
|
||||
"TTS not supported for this document": "TTS 不支援此文件",
|
||||
"Reset Password": "重設密碼",
|
||||
"Show Reading Progress": "顯示閱讀進度",
|
||||
"Show Progress Bar": "顯示進度列",
|
||||
"Reading Progress Style": "閱讀進度樣式",
|
||||
"Page Number": "頁碼",
|
||||
"Percentage": "百分比",
|
||||
@@ -1725,10 +1726,6 @@
|
||||
"Auto Sync": "自動同步",
|
||||
"Purged book data: {{title}}": "已清除書籍資料:{{title}}",
|
||||
"Failed to purge book data: {{title}}": "清除書籍資料失敗:{{title}}",
|
||||
"Purge Book Data": "清除書籍資料",
|
||||
"This permanently erases the book and all its data, including reading progress, notes, and bookmarks. This cannot be undone.": "這將永久刪除該書籍及其所有資料,包括閱讀進度、筆記和書籤。此操作無法復原。",
|
||||
"Purge Data": "清除資料",
|
||||
"Erase the book and all its data, including reading progress": "刪除該書籍及其所有資料,包括閱讀進度",
|
||||
"More Actions": "更多操作",
|
||||
"Sign in and make the book available to share it": "登入並使書籍可用後即可分享",
|
||||
"Download the book to export it": "下載書籍後即可匯出",
|
||||
@@ -1747,5 +1744,16 @@
|
||||
"Failed to save the image": "圖片儲存失敗",
|
||||
"Share Image": "分享圖片",
|
||||
"Save Image": "儲存圖片",
|
||||
"Image saved to gallery": "圖片已儲存至相簿"
|
||||
"Image saved to gallery": "圖片已儲存至相簿",
|
||||
"Please select a whole word or uncheck the \"Whole word\" option.": "請選取完整的單字,或取消勾選「全詞匹配」選項。",
|
||||
"Regex:": "正則:",
|
||||
"Invalid regular expression": "正規表示式無效",
|
||||
"Find pattern cannot be empty": "尋找內容不可為空",
|
||||
"Add Rule": "新增規則",
|
||||
"Find...": "尋找…",
|
||||
"Replace with...": "取代為…",
|
||||
"Purge & Delete": "清除並刪除",
|
||||
"Purge all reading data": "清除所有閱讀資料",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "這將永久清除閱讀進度、筆記和書籤,且無法復原。",
|
||||
"Also erase reading progress, notes, and bookmarks.": "同時清除閱讀進度、筆記和書籤。"
|
||||
}
|
||||
|
||||
@@ -227,6 +227,54 @@ describe('ProofreadPopup Component', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Regex Toggle', () => {
|
||||
it('should render the regex checkbox (off by default)', () => {
|
||||
renderWithProviders(<ProofreadPopup {...defaultProps} />);
|
||||
|
||||
const regexLabel = screen.getByText('Regex:');
|
||||
expect(regexLabel).toBeTruthy();
|
||||
const checkbox = regexLabel
|
||||
.closest('label')!
|
||||
.querySelector('input[type="checkbox"]') as HTMLInputElement | null;
|
||||
expect(checkbox).toBeTruthy();
|
||||
expect(checkbox!.checked).toBe(false);
|
||||
});
|
||||
|
||||
it('should call onConfirm with isRegex true when regex is enabled', async () => {
|
||||
renderWithProviders(<ProofreadPopup {...defaultProps} />);
|
||||
|
||||
const regexLabel = screen.getByText('Regex:');
|
||||
const regexCheckbox = regexLabel
|
||||
.closest('label')!
|
||||
.querySelector('input[type="checkbox"]') as HTMLInputElement;
|
||||
fireEvent.click(regexCheckbox);
|
||||
|
||||
const input = screen.getByPlaceholderText('Enter text...');
|
||||
fireEvent.change(input, { target: { value: 'replacement' } });
|
||||
|
||||
const applyButton = screen.getByText('Apply');
|
||||
fireEvent.click(applyButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnConfirm).toHaveBeenCalledWith(expect.objectContaining({ isRegex: true }));
|
||||
});
|
||||
});
|
||||
|
||||
it('should default isRegex to false when the toggle is left off', async () => {
|
||||
renderWithProviders(<ProofreadPopup {...defaultProps} />);
|
||||
|
||||
const input = screen.getByPlaceholderText('Enter text...');
|
||||
fireEvent.change(input, { target: { value: 'replacement' } });
|
||||
|
||||
const applyButton = screen.getByText('Apply');
|
||||
fireEvent.click(applyButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockOnConfirm).toHaveBeenCalledWith(expect.objectContaining({ isRegex: false }));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Click Outside Behavior', () => {
|
||||
it('should not call onClose when clicking inside the menu', () => {
|
||||
renderWithProviders(<ProofreadPopup {...defaultProps} />);
|
||||
|
||||
@@ -12,6 +12,8 @@ import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSidebarStore } from '@/store/sidebarStore';
|
||||
import { useBookDataStore } from '@/store/bookDataStore';
|
||||
import { useProofreadStore } from '@/store/proofreadStore';
|
||||
import { eventDispatcher } from '@/utils/event';
|
||||
import { ProofreadRule } from '@/types/book';
|
||||
|
||||
// ------------------------------
|
||||
@@ -97,6 +99,7 @@ describe('ProofreadRulesManager', () => {
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('renders book and library (global) proofreading rules from stores', async () => {
|
||||
@@ -245,6 +248,61 @@ describe('ProofreadRulesManager', () => {
|
||||
expect(screen.getByText("'book-hit'")).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders a drag handle for each reorderable rule', async () => {
|
||||
const selectionRule: ProofreadRule = {
|
||||
id: 's1',
|
||||
scope: 'selection',
|
||||
pattern: 'only-once',
|
||||
replacement: 'single-hit',
|
||||
enabled: true,
|
||||
isRegex: false,
|
||||
caseSensitive: true,
|
||||
order: 1,
|
||||
wholeWord: true,
|
||||
cfi: 'epubcfi(/6/14!/4/2,/1:0,/1:4)',
|
||||
sectionHref: 'chapter1.html',
|
||||
};
|
||||
const bookRule: ProofreadRule = {
|
||||
id: 'b1',
|
||||
scope: 'book',
|
||||
pattern: 'book-wide',
|
||||
replacement: 'book-hit',
|
||||
enabled: true,
|
||||
isRegex: false,
|
||||
caseSensitive: true,
|
||||
order: 2,
|
||||
wholeWord: true,
|
||||
};
|
||||
|
||||
(useSettingsStore.setState as unknown as (state: unknown) => void)({
|
||||
settings: { ...DEFAULT_SYSTEM_SETTINGS, globalViewSettings: { proofreadRules: [] } },
|
||||
});
|
||||
(useReaderStore.setState as unknown as (state: unknown) => void)({
|
||||
viewStates: { book1: { viewSettings: { proofreadRules: [selectionRule, bookRule] } } },
|
||||
});
|
||||
(useBookDataStore.setState as unknown as (state: unknown) => void)({
|
||||
booksData: {
|
||||
book1: {
|
||||
id: 'book1',
|
||||
book: null,
|
||||
file: null,
|
||||
config: { viewSettings: { proofreadRules: [selectionRule, bookRule] } },
|
||||
bookDoc: null,
|
||||
isFixedLayout: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
useSidebarStore.setState({ sideBarBookKey: 'book1' });
|
||||
|
||||
renderWithProviders(<ProofreadRulesManager />);
|
||||
await Promise.resolve();
|
||||
setProofreadRulesVisibility(true);
|
||||
await screen.findByRole('dialog');
|
||||
|
||||
const handles = screen.getAllByLabelText('Drag to reorder');
|
||||
expect(handles.length).toBe(2);
|
||||
});
|
||||
|
||||
it('displays correct scope labels for different rule types', async () => {
|
||||
const selectionRule: ProofreadRule = {
|
||||
id: 's1',
|
||||
@@ -484,6 +542,116 @@ describe('ProofreadRulesManager', () => {
|
||||
expect(screen.getByText('No book-level replacement rules')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('Add Rule form', () => {
|
||||
const openManagerForAdd = async () => {
|
||||
(useSettingsStore.setState as unknown as (state: unknown) => void)({
|
||||
settings: {
|
||||
...DEFAULT_SYSTEM_SETTINGS,
|
||||
globalViewSettings: { proofreadRules: [] },
|
||||
},
|
||||
});
|
||||
(useReaderStore.setState as unknown as (state: unknown) => void)({
|
||||
viewStates: { book1: { viewSettings: { proofreadRules: [] } } },
|
||||
});
|
||||
useSidebarStore.setState({ sideBarBookKey: 'book1' });
|
||||
|
||||
const addRuleSpy = vi
|
||||
.spyOn(useProofreadStore.getState(), 'addRule')
|
||||
.mockResolvedValue({} as ProofreadRule);
|
||||
const recreateSpy = vi
|
||||
.spyOn(useReaderStore.getState(), 'recreateViewer')
|
||||
.mockResolvedValue(undefined as never);
|
||||
|
||||
renderWithProviders(<ProofreadRulesManager />);
|
||||
await Promise.resolve();
|
||||
setProofreadRulesVisibility(true);
|
||||
await screen.findByRole('dialog');
|
||||
|
||||
return { addRuleSpy, recreateSpy };
|
||||
};
|
||||
|
||||
it('creates a book-scoped rule from typed pattern + replacement', async () => {
|
||||
const { addRuleSpy } = await openManagerForAdd();
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Find...'), { target: { value: 'colour' } });
|
||||
fireEvent.change(screen.getByPlaceholderText('Replace with...'), {
|
||||
target: { value: 'color' },
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Add Rule' }));
|
||||
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(addRuleSpy).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
'book1',
|
||||
expect.objectContaining({
|
||||
scope: 'book',
|
||||
pattern: 'colour',
|
||||
replacement: 'color',
|
||||
isRegex: false,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('creates a regex rule when the Regex toggle is on', async () => {
|
||||
const { addRuleSpy } = await openManagerForAdd();
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Find...'), { target: { value: '\\d+' } });
|
||||
fireEvent.change(screen.getByPlaceholderText('Replace with...'), {
|
||||
target: { value: '#' },
|
||||
});
|
||||
const regexLabel = screen.getByText('Regex:');
|
||||
const regexCheckbox = regexLabel
|
||||
.closest('label')!
|
||||
.querySelector('input[type="checkbox"]') as HTMLInputElement;
|
||||
fireEvent.click(regexCheckbox);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Add Rule' }));
|
||||
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(addRuleSpy).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
'book1',
|
||||
expect.objectContaining({ pattern: '\\d+', isRegex: true }),
|
||||
);
|
||||
});
|
||||
|
||||
it('disables the Add Rule button until a find pattern is entered', async () => {
|
||||
const { addRuleSpy } = await openManagerForAdd();
|
||||
const button = screen.getByRole('button', { name: 'Add Rule' }) as HTMLButtonElement;
|
||||
|
||||
expect(button.disabled).toBe(true);
|
||||
fireEvent.click(button);
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
expect(addRuleSpy).not.toHaveBeenCalled();
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Find...'), { target: { value: 'colour' } });
|
||||
expect(button.disabled).toBe(false);
|
||||
});
|
||||
|
||||
it('warns and does not add when the regex is invalid', async () => {
|
||||
const { addRuleSpy } = await openManagerForAdd();
|
||||
const dispatchSpy = vi.spyOn(eventDispatcher, 'dispatch');
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('Find...'), { target: { value: '(' } });
|
||||
const regexLabel = screen.getByText('Regex:');
|
||||
const regexCheckbox = regexLabel
|
||||
.closest('label')!
|
||||
.querySelector('input[type="checkbox"]') as HTMLInputElement;
|
||||
fireEvent.click(regexCheckbox);
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Add Rule' }));
|
||||
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
expect(addRuleSpy).not.toHaveBeenCalled();
|
||||
expect(dispatchSpy).toHaveBeenCalledWith(
|
||||
'toast',
|
||||
expect.objectContaining({ type: 'warning' }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('merges book and library rules correctly in book section', async () => {
|
||||
const libraryRule: ProofreadRule = {
|
||||
id: 'l1',
|
||||
|
||||
@@ -146,6 +146,58 @@ describe('SETTINGS_WHITELIST', () => {
|
||||
test('does NOT sync dictionarySettings.defaultProviderId (per-device last-used tab)', () => {
|
||||
expect(SETTINGS_WHITELIST).not.toContain('dictionarySettings.defaultProviderId');
|
||||
});
|
||||
|
||||
test('syncs library-scope proofread rules (issue #4700 — PC rules not reaching mobile)', () => {
|
||||
expect(SETTINGS_WHITELIST).toContain('globalViewSettings.proofreadRules');
|
||||
});
|
||||
});
|
||||
|
||||
describe('settingsAdapter proofread rules', () => {
|
||||
test('pack ∘ unpack round-trips globalViewSettings.proofreadRules', () => {
|
||||
const proofreadRules = [
|
||||
{
|
||||
id: 'r1',
|
||||
scope: 'library',
|
||||
pattern: 'colour',
|
||||
replacement: 'color',
|
||||
enabled: true,
|
||||
isRegex: false,
|
||||
caseSensitive: true,
|
||||
order: 1000,
|
||||
wholeWord: true,
|
||||
},
|
||||
];
|
||||
const record: SettingsRemoteRecord = {
|
||||
name: 'singleton',
|
||||
patch: {
|
||||
globalViewSettings: { proofreadRules },
|
||||
} as unknown as Partial<SystemSettings>,
|
||||
};
|
||||
const fields = settingsAdapter.pack(record);
|
||||
expect(fields['globalViewSettings.proofreadRules']).toEqual(proofreadRules);
|
||||
const out = settingsAdapter.unpack(fields);
|
||||
expect(out.patch.globalViewSettings?.proofreadRules).toEqual(proofreadRules);
|
||||
});
|
||||
|
||||
test('unpackRow reconstructs proofread rules from a CRDT envelope', () => {
|
||||
const proofreadRules = [
|
||||
{
|
||||
id: 'r1',
|
||||
scope: 'library',
|
||||
pattern: 'teh',
|
||||
replacement: 'the',
|
||||
enabled: true,
|
||||
isRegex: false,
|
||||
caseSensitive: false,
|
||||
order: 1000,
|
||||
wholeWord: true,
|
||||
},
|
||||
];
|
||||
const row = makeRow({ 'globalViewSettings.proofreadRules': env(proofreadRules) });
|
||||
const out = settingsAdapter.unpackRow(row, '');
|
||||
expect(out).not.toBeNull();
|
||||
expect(out!.patch.globalViewSettings?.proofreadRules).toEqual(proofreadRules);
|
||||
});
|
||||
});
|
||||
|
||||
describe('readPath / writePath', () => {
|
||||
|
||||
@@ -503,4 +503,87 @@ describe('proofreadStore', () => {
|
||||
).rejects.toThrow('Rule not found: no-exist');
|
||||
});
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// reorderRules
|
||||
// -----------------------------------------------------------------------
|
||||
describe('reorderRules', () => {
|
||||
test('reassigns order fields for book-scope rules by position; saves config only', async () => {
|
||||
mockViewSettingsMap['book1'] = emptyViewSettings({
|
||||
proofreadRules: [
|
||||
makeRule({ id: 'a', scope: 'book', order: 1000 }),
|
||||
makeRule({ id: 'b', scope: 'book', order: 1000 }),
|
||||
makeRule({ id: 'c', scope: 'book', order: 1000 }),
|
||||
],
|
||||
});
|
||||
|
||||
await useProofreadStore.getState().reorderRules(envConfig, 'book1', ['c', 'a', 'b']);
|
||||
|
||||
const saved = mockViewSettingsMap['book1']!.proofreadRules!;
|
||||
const orderById = Object.fromEntries(saved.map((r) => [r.id, r.order]));
|
||||
expect(orderById).toEqual({ c: 0, a: 1, b: 2 });
|
||||
expect(mockSaveConfig).toHaveBeenCalledTimes(1);
|
||||
expect(mockSaveSettings).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('reassigns order for library-scope rules; saves settings only', async () => {
|
||||
mockViewSettingsMap['book1'] = emptyViewSettings({ proofreadRules: [] });
|
||||
mockGlobalViewSettingsHolder.current = emptyViewSettings({
|
||||
proofreadRules: [
|
||||
makeRule({ id: 'g1', scope: 'library', order: 1000 }),
|
||||
makeRule({ id: 'g2', scope: 'library', order: 1000 }),
|
||||
],
|
||||
});
|
||||
|
||||
await useProofreadStore.getState().reorderRules(envConfig, 'book1', ['g2', 'g1']);
|
||||
|
||||
const savedSettings = mockSaveSettings.mock.calls[0]![1] as {
|
||||
globalViewSettings: ViewSettings;
|
||||
};
|
||||
const saved = savedSettings.globalViewSettings.proofreadRules!;
|
||||
const orderById = Object.fromEntries(saved.map((r) => [r.id, r.order]));
|
||||
expect(orderById).toEqual({ g2: 0, g1: 1 });
|
||||
expect(mockSaveSettings).toHaveBeenCalledTimes(1);
|
||||
expect(mockSaveConfig).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('a merged book+library reorder updates both stores', async () => {
|
||||
mockViewSettingsMap['book1'] = emptyViewSettings({
|
||||
proofreadRules: [makeRule({ id: 'bk', scope: 'book', order: 1000 })],
|
||||
});
|
||||
mockGlobalViewSettingsHolder.current = emptyViewSettings({
|
||||
proofreadRules: [makeRule({ id: 'lib', scope: 'library', order: 1000 })],
|
||||
});
|
||||
|
||||
// Drag the library rule above the book rule.
|
||||
await useProofreadStore.getState().reorderRules(envConfig, 'book1', ['lib', 'bk']);
|
||||
|
||||
const savedBook = mockViewSettingsMap['book1']!.proofreadRules!.find((r) => r.id === 'bk');
|
||||
const savedSettings = mockSaveSettings.mock.calls[0]![1] as {
|
||||
globalViewSettings: ViewSettings;
|
||||
};
|
||||
const savedLib = savedSettings.globalViewSettings.proofreadRules!.find((r) => r.id === 'lib');
|
||||
expect(savedLib!.order).toBe(0);
|
||||
expect(savedBook!.order).toBe(1);
|
||||
expect(mockSaveConfig).toHaveBeenCalledTimes(1);
|
||||
expect(mockSaveSettings).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('leaves rules outside the reordered set untouched', async () => {
|
||||
mockViewSettingsMap['book1'] = emptyViewSettings({
|
||||
proofreadRules: [
|
||||
makeRule({ id: 'sel', scope: 'selection', order: 7 }),
|
||||
makeRule({ id: 'a', scope: 'book', order: 1000 }),
|
||||
makeRule({ id: 'b', scope: 'book', order: 1000 }),
|
||||
],
|
||||
});
|
||||
|
||||
await useProofreadStore.getState().reorderRules(envConfig, 'book1', ['b', 'a']);
|
||||
|
||||
const saved = mockViewSettingsMap['book1']!.proofreadRules!;
|
||||
expect(saved.find((r) => r.id === 'sel')!.order).toBe(7);
|
||||
expect(saved.find((r) => r.id === 'b')!.order).toBe(0);
|
||||
expect(saved.find((r) => r.id === 'a')!.order).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { RiEditLine, RiDeleteBin7Line } from 'react-icons/ri';
|
||||
import { MdDragIndicator } from 'react-icons/md';
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
TouchSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
type DragEndEvent,
|
||||
type Modifier,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
useSortable,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSidebarStore } from '@/store/sidebarStore';
|
||||
import { useBookDataStore } from '@/store/bookDataStore';
|
||||
import { useProofreadStore } from '@/store/proofreadStore';
|
||||
import { useProofreadStore, validateReplacementRulePattern } from '@/store/proofreadStore';
|
||||
import { ProofreadRule, ProofreadScope } from '@/types/book';
|
||||
import { eventDispatcher } from '@/utils/event';
|
||||
import Dialog from '@/components/Dialog';
|
||||
import { SectionTitle } from '@/components/settings/primitives';
|
||||
|
||||
const dialogId = 'proofread_rules_window';
|
||||
|
||||
@@ -21,6 +41,29 @@ export const setProofreadRulesVisibility = (visible: boolean) => {
|
||||
}
|
||||
};
|
||||
|
||||
const byOrder = (a: ProofreadRule, b: ProofreadRule): number => (a.order ?? 0) - (b.order ?? 0);
|
||||
|
||||
// Lock drag travel to the vertical axis — the lists are vertical, so any
|
||||
// horizontal motion just lets the drag preview drift out from under the row.
|
||||
const restrictToVerticalAxis: Modifier = ({ transform }) => ({ ...transform, x: 0 });
|
||||
|
||||
// Clamp the drag preview to the list container so a row can't be dragged out.
|
||||
const restrictToParentElement: Modifier = ({ containerNodeRect, draggingNodeRect, transform }) => {
|
||||
if (!draggingNodeRect || !containerNodeRect) return transform;
|
||||
const value = { ...transform };
|
||||
if (draggingNodeRect.top + transform.y < containerNodeRect.top) {
|
||||
value.y = containerNodeRect.top - draggingNodeRect.top;
|
||||
} else if (
|
||||
draggingNodeRect.bottom + transform.y >
|
||||
containerNodeRect.top + containerNodeRect.height
|
||||
) {
|
||||
value.y = containerNodeRect.top + containerNodeRect.height - draggingNodeRect.bottom;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const dragModifiers: Modifier[] = [restrictToVerticalAxis, restrictToParentElement];
|
||||
|
||||
const RuleItem: React.FC<{
|
||||
rule: ProofreadRule;
|
||||
scope: ProofreadScope;
|
||||
@@ -145,6 +188,53 @@ const RuleItem: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// Sortable wrapper: the draggable `<li>` chassis + a left drag handle around
|
||||
// the existing RuleItem. The handle is the only drag-listener surface so the
|
||||
// edit/delete buttons stay clickable; it's hidden while the row is in edit mode.
|
||||
const SortableRuleItem: React.FC<React.ComponentProps<typeof RuleItem>> = (props) => {
|
||||
const _ = useTranslation();
|
||||
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
||||
id: props.rule.id,
|
||||
});
|
||||
const style: React.CSSProperties = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
opacity: isDragging ? 0.6 : 1,
|
||||
};
|
||||
|
||||
return (
|
||||
<li
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
className={clsx(
|
||||
'card eink-bordered border-base-200 bg-base-100 border transition-colors',
|
||||
isDragging ? 'z-10 shadow-md' : 'hover:border-base-300',
|
||||
)}
|
||||
>
|
||||
<div className='flex items-stretch'>
|
||||
{!props.isEditing && (
|
||||
<button
|
||||
type='button'
|
||||
className={clsx(
|
||||
'touch-target text-base-content/35 hover:text-base-content/70 flex w-7 shrink-0',
|
||||
'cursor-grab touch-none items-center justify-center active:cursor-grabbing',
|
||||
)}
|
||||
aria-label={_('Drag to reorder')}
|
||||
title={_('Drag to reorder')}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
>
|
||||
<MdDragIndicator className='h-4 w-4' />
|
||||
</button>
|
||||
)}
|
||||
<div className='min-w-0 flex-1'>
|
||||
<RuleItem {...props} />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
// Hook to manage rules logic
|
||||
const useReplacementRules = (bookKey: string | null) => {
|
||||
const { settings } = useSettingsStore();
|
||||
@@ -159,7 +249,9 @@ const useReplacementRules = (bookKey: string | null) => {
|
||||
// Prefer persisted rules; fall back to in-memory
|
||||
const bookRuleSource = persistedBookRules.length ? persistedBookRules : inMemoryRules;
|
||||
|
||||
const singleRules = bookRuleSource.filter((r: ProofreadRule) => r.scope === 'selection');
|
||||
const singleRules = bookRuleSource
|
||||
.filter((r: ProofreadRule) => r.scope === 'selection')
|
||||
.sort(byOrder);
|
||||
const bookScopedRules = bookRuleSource.filter((r: ProofreadRule) => r.scope === 'book');
|
||||
const globalRules = settings?.globalViewSettings?.proofreadRules || [];
|
||||
|
||||
@@ -171,11 +263,16 @@ const useReplacementRules = (bookKey: string | null) => {
|
||||
(br: ProofreadRule) => br.enabled !== false || globalRuleIds.has(br.id),
|
||||
);
|
||||
|
||||
const mergedBookRules = validBookRules.concat(
|
||||
globalRules.filter(
|
||||
(gr: ProofreadRule) => !validBookRules.find((br: ProofreadRule) => br.id === gr.id),
|
||||
),
|
||||
);
|
||||
// Sort by `order` so a drag-to-reorder (which rewrites the order field)
|
||||
// persists visually; the stable sort keeps insertion order while every
|
||||
// rule still shares the default order.
|
||||
const mergedBookRules = validBookRules
|
||||
.concat(
|
||||
globalRules.filter(
|
||||
(gr: ProofreadRule) => !validBookRules.find((br: ProofreadRule) => br.id === gr.id),
|
||||
),
|
||||
)
|
||||
.sort(byOrder);
|
||||
|
||||
return { singleRules, bookRules: mergedBookRules };
|
||||
};
|
||||
@@ -185,9 +282,23 @@ export const ProofreadRulesManager: React.FC = () => {
|
||||
const { envConfig } = useEnv();
|
||||
const { recreateViewer } = useReaderStore();
|
||||
const { sideBarBookKey } = useSidebarStore();
|
||||
const { updateRule, removeRule } = useProofreadStore();
|
||||
const { addRule, updateRule, removeRule, reorderRules } = useProofreadStore();
|
||||
|
||||
// dnd-kit sensors mirror the dictionaries reorder list: a small pointer
|
||||
// distance gate avoids hijacking handle clicks, a touch delay gives mobile
|
||||
// long-press-to-drag, and the keyboard sensor makes reordering accessible.
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
|
||||
useSensor(TouchSensor, { activationConstraint: { delay: 200, tolerance: 5 } }),
|
||||
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
|
||||
);
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [addPattern, setAddPattern] = useState('');
|
||||
const [addReplacement, setAddReplacement] = useState('');
|
||||
const [addScope, setAddScope] = useState<Exclude<ProofreadScope, 'selection'>>('book');
|
||||
const [addIsRegex, setAddIsRegex] = useState(false);
|
||||
const [addCaseSensitive, setAddCaseSensitive] = useState(true);
|
||||
const [editing, setEditing] = useState<{
|
||||
id: string | null;
|
||||
scope: ProofreadScope | null;
|
||||
@@ -255,42 +366,89 @@ export const ProofreadRulesManager: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddRule = async () => {
|
||||
if (!sideBarBookKey) return;
|
||||
const pattern = addPattern.trim();
|
||||
const validation = validateReplacementRulePattern(pattern, addIsRegex);
|
||||
if (!validation.valid) {
|
||||
eventDispatcher.dispatch('toast', {
|
||||
type: 'warning',
|
||||
message: pattern ? _('Invalid regular expression') : _('Find pattern cannot be empty'),
|
||||
timeout: 3000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await addRule(envConfig, sideBarBookKey, {
|
||||
scope: addScope,
|
||||
pattern,
|
||||
replacement: addReplacement.trim(),
|
||||
isRegex: addIsRegex,
|
||||
caseSensitive: addCaseSensitive,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
setAddPattern('');
|
||||
setAddReplacement('');
|
||||
setAddIsRegex(false);
|
||||
recreateViewer(envConfig, sideBarBookKey);
|
||||
};
|
||||
|
||||
const handleDragEnd = async (event: DragEndEvent, list: ProofreadRule[]) => {
|
||||
const { active, over } = event;
|
||||
if (!over || active.id === over.id || !sideBarBookKey) return;
|
||||
const ids = list.map((r) => r.id);
|
||||
const fromIdx = ids.indexOf(String(active.id));
|
||||
const toIdx = ids.indexOf(String(over.id));
|
||||
if (fromIdx < 0 || toIdx < 0) return;
|
||||
const [moved] = ids.splice(fromIdx, 1);
|
||||
if (!moved) return;
|
||||
ids.splice(toIdx, 0, moved);
|
||||
await reorderRules(envConfig, sideBarBookKey, ids);
|
||||
recreateViewer(envConfig, sideBarBookKey);
|
||||
};
|
||||
|
||||
const renderRuleList = (
|
||||
rules: ProofreadRule[],
|
||||
scopeType: ProofreadScope,
|
||||
title: string,
|
||||
emptyMessage: string,
|
||||
) => (
|
||||
<div className='flex flex-col gap-3'>
|
||||
<h3 className='text-base-content/90 text-sm font-semibold'>{title}</h3>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<SectionTitle>{title}</SectionTitle>
|
||||
{rules.length === 0 ? (
|
||||
<div className='border-base-content/10 bg-base-200/30 rounded-lg border border-dashed p-6 text-center'>
|
||||
<div className='border-base-300 bg-base-200/30 rounded-xl border border-dashed p-6 text-center'>
|
||||
<p className='text-base-content/50 text-sm'>{emptyMessage}</p>
|
||||
</div>
|
||||
) : (
|
||||
<ul className='flex flex-col gap-2'>
|
||||
{rules.map((rule) => (
|
||||
<li
|
||||
key={rule.id}
|
||||
className='border-base-content/10 bg-base-100 hover:border-base-content/20 rounded-lg border transition-colors'
|
||||
>
|
||||
<RuleItem
|
||||
rule={rule}
|
||||
scope={scopeType === 'selection' ? 'selection' : rule.scope}
|
||||
isEditing={
|
||||
editing.id === rule.id &&
|
||||
editing.scope === (scopeType === 'selection' ? 'selection' : rule.scope)
|
||||
}
|
||||
editingData={editing}
|
||||
onEdit={() => startEdit(rule)}
|
||||
onDelete={() => deleteRule(rule)}
|
||||
onSave={saveEdit}
|
||||
onCancel={cancelEdit}
|
||||
onEditChange={(_, value) => setEditing({ ...editing, replacement: value })}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
collisionDetection={closestCenter}
|
||||
modifiers={dragModifiers}
|
||||
onDragEnd={(event) => handleDragEnd(event, rules)}
|
||||
>
|
||||
<SortableContext items={rules.map((r) => r.id)} strategy={verticalListSortingStrategy}>
|
||||
<ul className='flex flex-col gap-2'>
|
||||
{rules.map((rule) => (
|
||||
<SortableRuleItem
|
||||
key={rule.id}
|
||||
rule={rule}
|
||||
scope={scopeType === 'selection' ? 'selection' : rule.scope}
|
||||
isEditing={
|
||||
editing.id === rule.id &&
|
||||
editing.scope === (scopeType === 'selection' ? 'selection' : rule.scope)
|
||||
}
|
||||
editingData={editing}
|
||||
onEdit={() => startEdit(rule)}
|
||||
onDelete={() => deleteRule(rule)}
|
||||
onSave={saveEdit}
|
||||
onCancel={cancelEdit}
|
||||
onEditChange={(_, value) => setEditing({ ...editing, replacement: value })}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
@@ -301,10 +459,81 @@ export const ProofreadRulesManager: React.FC = () => {
|
||||
isOpen={isOpen}
|
||||
onClose={() => setIsOpen(false)}
|
||||
title={_('Proofread Replacement Rules')}
|
||||
boxClassName='sm:!min-w-[560px] sm:!max-w-[640px] sm:h-auto'
|
||||
// Cap the height on desktop (where the modal is auto-height) so the body
|
||||
// scrolls; on mobile the modal is full-height and the body fills it.
|
||||
boxClassName='sm:!min-w-[560px] sm:!max-w-[640px] sm:h-auto sm:!max-h-[80vh]'
|
||||
// Drop the body's default horizontal padding so the scrollbar rides the
|
||||
// modal's right edge (the inner `p-4 sm:p-6` keeps content off it), and
|
||||
// `min-h-0` lets the flex-grow body shrink-to-scroll inside the capped
|
||||
// modal instead of overflowing.
|
||||
contentClassName='!px-0 min-h-0'
|
||||
>
|
||||
{isOpen && (
|
||||
<div className='flex max-h-[70vh] flex-col gap-6 p-4 sm:p-6'>
|
||||
<div className='flex flex-col gap-6 p-4 sm:p-6'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<SectionTitle>{_('Add Rule')}</SectionTitle>
|
||||
<div className='card eink-bordered border-base-200 bg-base-100 gap-3 border p-4'>
|
||||
<input
|
||||
className='input input-bordered eink-bordered h-11 w-full text-sm focus:outline-none'
|
||||
placeholder={_('Find...')}
|
||||
spellCheck='false'
|
||||
value={addPattern}
|
||||
onChange={(e) => setAddPattern(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
className='input input-bordered eink-bordered h-11 w-full text-sm focus:outline-none'
|
||||
placeholder={_('Replace with...')}
|
||||
spellCheck='false'
|
||||
value={addReplacement}
|
||||
onChange={(e) => setAddReplacement(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') handleAddRule();
|
||||
}}
|
||||
/>
|
||||
<div className='flex flex-wrap items-center gap-x-5 gap-y-3 pt-0.5'>
|
||||
<label className='flex items-center gap-2'>
|
||||
<span className='text-base-content/70 text-sm'>{_('Scope:')}</span>
|
||||
<select
|
||||
className='select select-sm select-bordered eink-bordered min-h-9 h-9'
|
||||
value={addScope}
|
||||
onChange={(e) =>
|
||||
setAddScope(e.target.value as Exclude<ProofreadScope, 'selection'>)
|
||||
}
|
||||
>
|
||||
<option value='book'>{_('Book')}</option>
|
||||
<option value='library'>{_('Library')}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label className='flex cursor-pointer items-center gap-2'>
|
||||
<span className='text-base-content/70 text-sm'>{_('Regex:')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle toggle-sm'
|
||||
checked={addIsRegex}
|
||||
onChange={(e) => setAddIsRegex(e.target.checked)}
|
||||
/>
|
||||
</label>
|
||||
<label className='flex cursor-pointer items-center gap-2'>
|
||||
<span className='text-base-content/70 text-sm'>{_('Case sensitive:')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle toggle-sm'
|
||||
checked={addCaseSensitive}
|
||||
onChange={(e) => setAddCaseSensitive(e.target.checked)}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div className='border-base-200 mt-1 flex justify-end border-t pt-3'>
|
||||
<button
|
||||
className='btn btn-contrast h-10 min-h-10 rounded-lg px-5 text-sm font-medium disabled:opacity-40'
|
||||
onClick={handleAddRule}
|
||||
disabled={!addPattern.trim()}
|
||||
>
|
||||
{_('Add Rule')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{renderRuleList(
|
||||
singleRules,
|
||||
'selection',
|
||||
|
||||
@@ -1259,7 +1259,12 @@ const Annotator: React.FC<{ bookKey: string; contentInsets: Insets }> = ({
|
||||
};
|
||||
|
||||
const handleProofread = () => {
|
||||
if (!selection || !selection.text) return;
|
||||
// With no active selection the shortcut (Ctrl/Cmd+P) has nothing to turn
|
||||
// into a rule, so reuse it to open the replacement-rules manager instead.
|
||||
if (!selection || !selection.text) {
|
||||
setProofreadRulesVisibility(true);
|
||||
return;
|
||||
}
|
||||
setShowAnnotPopup(false);
|
||||
setShowProofreadPopup(true);
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ const ProofreadPopup: React.FC<ProofreadPopupProps> = ({
|
||||
const [replacementText, setReplacementText] = useState('');
|
||||
const [caseSensitive, setCaseSensitive] = useState(true);
|
||||
const [wholeWord, setWholeWord] = useState(!isPunctuationOnly(selection?.text || ''));
|
||||
const [isRegex, setIsRegex] = useState(false);
|
||||
const [scope, setScope] = useState<ProofreadScope>('selection');
|
||||
const [onlyForTTS, setOnlyForTTS] = useState(false);
|
||||
|
||||
@@ -66,12 +67,14 @@ const ProofreadPopup: React.FC<ProofreadPopupProps> = ({
|
||||
const range = selection?.range;
|
||||
|
||||
if (range) {
|
||||
// A regex pattern defines its own boundaries, so the whole-word
|
||||
// validation (which inspects the literal selection) doesn't apply.
|
||||
const isValidWholeWord = isWholeWord(range, selection?.text || '');
|
||||
|
||||
if (wholeWord && !isValidWholeWord) {
|
||||
if (!isRegex && wholeWord && !isValidWholeWord) {
|
||||
eventDispatcher.dispatch('toast', {
|
||||
type: 'warning',
|
||||
message: 'Please select a whole word or uncheck the "Whole word" option.',
|
||||
message: _('Please select a whole word or uncheck the "Whole word" option.'),
|
||||
timeout: 5000,
|
||||
});
|
||||
return;
|
||||
@@ -89,10 +92,10 @@ const ProofreadPopup: React.FC<ProofreadPopupProps> = ({
|
||||
replacement: replacementText.trim(),
|
||||
cfi: selection.cfi,
|
||||
sectionHref: progress?.sectionHref,
|
||||
isRegex: false,
|
||||
isRegex,
|
||||
enabled: true,
|
||||
caseSensitive,
|
||||
wholeWord: wholeWord,
|
||||
wholeWord: isRegex ? false : wholeWord,
|
||||
onlyForTTS: scope !== 'selection' ? onlyForTTS : undefined,
|
||||
};
|
||||
onConfirm?.(options);
|
||||
@@ -196,10 +199,33 @@ const ProofreadPopup: React.FC<ProofreadPopupProps> = ({
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label className='flex cursor-pointer items-center gap-2'>
|
||||
<label
|
||||
className={clsx(
|
||||
'flex items-center gap-2',
|
||||
isRegex ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',
|
||||
)}
|
||||
>
|
||||
<span className='line-clamp-1 text-xs' title={_('Whole word:')}>
|
||||
{_('Whole word:')}
|
||||
</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
disabled={isRegex}
|
||||
className='toggle toggle-sm bg-gray-500 checked:bg-black hover:bg-gray-500 hover:checked:bg-black'
|
||||
style={
|
||||
{
|
||||
'--tglbg': '#4B5563',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
checked={isRegex ? false : wholeWord}
|
||||
onChange={(e) => setWholeWord(e.target.checked)}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label className='flex cursor-pointer items-center gap-2'>
|
||||
<span className='line-clamp-1 text-xs' title={_('Regex:')}>
|
||||
{_('Regex:')}
|
||||
</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle toggle-sm bg-gray-500 checked:bg-black hover:bg-gray-500 hover:checked:bg-black'
|
||||
@@ -208,8 +234,8 @@ const ProofreadPopup: React.FC<ProofreadPopupProps> = ({
|
||||
'--tglbg': '#4B5563',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
checked={wholeWord}
|
||||
onChange={(e) => setWholeWord(e.target.checked)}
|
||||
checked={isRegex}
|
||||
onChange={(e) => setIsRegex(e.target.checked)}
|
||||
/>
|
||||
</label>
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ export const SETTINGS_REPLICA_ID = 'singleton';
|
||||
export const SETTINGS_WHITELIST = [
|
||||
'globalViewSettings.userStylesheet',
|
||||
'globalViewSettings.userUIStylesheet',
|
||||
// Library-scope proofread (find/replace) rules. Whole-field LWW like the
|
||||
// other arrays here. Book- and selection-scope rules already ride along the
|
||||
// book config sync; only these global rules were stranded on one device.
|
||||
'globalViewSettings.proofreadRules',
|
||||
'globalReadSettings.customThemes',
|
||||
'globalReadSettings.customHighlightColors',
|
||||
'globalReadSettings.userHighlightColors',
|
||||
|
||||
@@ -44,6 +44,14 @@ interface ProofreadStoreState {
|
||||
scope: ProofreadScope,
|
||||
) => Promise<void>;
|
||||
toggleRule: (envConfig: EnvConfigType, bookKey: string, ruleId: string) => Promise<void>;
|
||||
/**
|
||||
* Persist a drag-to-reorder of one rule category. `orderedIds` is the new
|
||||
* visual order of the category's rules; each matching rule's `order` field
|
||||
* is set to its index. A category can span both stores (book + library), so
|
||||
* book/selection rules are written to the book config and library rules to
|
||||
* the global settings — only the store(s) actually touched are saved.
|
||||
*/
|
||||
reorderRules: (envConfig: EnvConfigType, bookKey: string, orderedIds: string[]) => Promise<void>;
|
||||
}
|
||||
|
||||
function createProofreadRule(opts: CreateProofreadRuleOptions): ProofreadRule {
|
||||
@@ -135,6 +143,36 @@ export const useProofreadStore = create<ProofreadStoreState>(() => ({
|
||||
const { updateRule } = useProofreadStore.getState();
|
||||
await updateRule(envConfig, bookKey, ruleId, { enabled: !rule.enabled });
|
||||
},
|
||||
|
||||
reorderRules: async (envConfig, bookKey, orderedIds) => {
|
||||
const orderById = new Map(orderedIds.map((id, index) => [id, index] as const));
|
||||
|
||||
const { getViewSettings } = useReaderStore.getState();
|
||||
const viewSettings = getViewSettings(bookKey);
|
||||
if (viewSettings) {
|
||||
let bookTouched = false;
|
||||
const updated = (viewSettings.proofreadRules || []).map((r) => {
|
||||
const order = orderById.get(r.id);
|
||||
if (order === undefined) return r;
|
||||
bookTouched = true;
|
||||
return { ...r, order };
|
||||
});
|
||||
if (bookTouched) await updateBookViewSettings(envConfig, bookKey, updated);
|
||||
}
|
||||
|
||||
const { settings } = useSettingsStore.getState();
|
||||
const globalRules = settings.globalViewSettings?.proofreadRules;
|
||||
if (globalRules?.length) {
|
||||
let globalTouched = false;
|
||||
const updated = globalRules.map((r) => {
|
||||
const order = orderById.get(r.id);
|
||||
if (order === undefined) return r;
|
||||
globalTouched = true;
|
||||
return { ...r, order };
|
||||
});
|
||||
if (globalTouched) await updateGlobalSettings(envConfig, updated);
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
async function addBookRule(
|
||||
|
||||
Reference in New Issue
Block a user