refactor(settings): polish sync and integration panels (#4774)
- Background Image: move the Library/Reader scope into the section title
("Background Image (Library)" and "Background Image (Reader)") instead
of a separate "Applies to ..." sublabel line.
- Send to Readest: render approved-sender emails monospace to match the
inbound address, and wrap long addresses to at most two lines instead
of truncating on one line.
- WebDAV: split the "Uploading X / Y" progress into a status line plus a
one-line book title.
- WebDAV: reword the "Upload Book Files" description to "Uploads book
files to your other devices."
- WebDAV: rename the "Always use latest" strategy to "Send and receive".
KOSync keeps "Always use latest" since it must contrast with its
"Ask on conflict" option.
- WebDAV: remove the Sync History section and its persisted log model;
the sync engine still reports per-book failures in its result.
Updated i18n across all 33 locales.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -479,6 +479,7 @@
|
||||
"Sync Strategy": "استراتيجية المزامنة",
|
||||
"Ask on conflict": "اسأل عند حدوث تعارض",
|
||||
"Always use latest": "استخدام الأحدث دائمًا",
|
||||
"Send and receive": "إرسال واستلام",
|
||||
"Send changes only": "إرسال التغييرات فقط",
|
||||
"Receive changes only": "استلام التغييرات فقط",
|
||||
"Checksum Method": "طريقة التحقق من الصحة",
|
||||
@@ -1721,8 +1722,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "تم نسيان عبارة المرور للمزامنة. تم مسح جميع الحقول المشفرة.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "المزامنات اليدوية والتنظيف فقط. لا تُسجل المزامنات التلقائية أثناء القراءة هنا.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "هل تريد حذف {{n}} كتاب/كتب من خادم WebDAV؟\n\nهذا يحذف الملفات البعيدة فقط؛ مكتبتك المحلية لن تتأثر. لا يمكن التراجع عن الحذف. البيانات على الخادم ستزول للأبد.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "يؤثر فقط على تحميل ملفات الكتب. يتم دائمًا مزامنة تقدم القراءة والتنزيلات.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "يرفع ملفات الكتب إلى أجهزتك الأخرى.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "عبارة مرور المزامنة غير صحيحة. تعذر فك تشفير بيانات الاعتماد المتزامنة.",
|
||||
"Email books straight to your library": "أرسل الكتب مباشرة إلى مكتبتك عبر البريد الإلكتروني",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "أعد توجيه المرفقات والمقالات إلى عنوان Readest الخاص بك. متوفر في خطط Plus وPro وLifetime.",
|
||||
@@ -1921,6 +1922,6 @@
|
||||
"Purge all reading data": "مسح جميع بيانات القراءة",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "يؤدي هذا إلى مسح تقدم القراءة والملاحظات والإشارات المرجعية نهائيًا. لا يمكن التراجع عن هذا الإجراء.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "يمسح أيضًا تقدم القراءة والملاحظات والإشارات المرجعية.",
|
||||
"Applies to the Library": "يُطبَّق على المكتبة",
|
||||
"Applies to the Reader": "يُطبَّق على واجهة القراءة"
|
||||
"Background Image (Library)": "صورة الخلفية (المكتبة)",
|
||||
"Background Image (Reader)": "صورة الخلفية (واجهة القراءة)"
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"Sync Strategy": "সিঙ্ক কৌশল",
|
||||
"Ask on conflict": "দ্বন্দ্বে জিজ্ঞাসা করুন",
|
||||
"Always use latest": "সবসময় সর্বশেষ ব্যবহার করুন",
|
||||
"Send and receive": "পাঠানো এবং গ্রহণ করা",
|
||||
"Send changes only": "শুধু পরিবর্তন পাঠান",
|
||||
"Receive changes only": "শুধু পরিবর্তন গ্রহণ করুন",
|
||||
"Checksum Method": "চেকসাম পদ্ধতি",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "সিঙ্ক পাসফ্রেজ ভুলে যাওয়া হয়েছে। সমস্ত এনক্রিপ্ট করা ফিল্ড পরিষ্কার করা হয়েছে।",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "শুধুমাত্র ম্যানুয়াল সিঙ্ক এবং পরিচ্ছন্নতা। পড়ার সময় স্বয়ংক্রিয় সিঙ্ক এখানে লগ হয় না।",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV সার্ভার থেকে {{n}}টি বই মুছে ফেলবেন?\n\nএটি শুধু রিমোট ফাইল মুছে; আপনার স্থানীয় লাইব্রেরি অপরিবর্তিত থাকে। মুছে ফেলা পূর্বাবস্থায় ফেরানো যাবে না। সার্ভারের ডেটা স্থায়ীভাবে চলে যাবে।",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "শুধুমাত্র বইয়ের ফাইল আপলোডকে প্রভাবিত করে। পড়ার অগ্রগতি এবং ডাউনলোড সবসময় সিঙ্ক হয়।",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "আপনার অন্যান্য ডিভাইসে বইয়ের ফাইল আপলোড করে।",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "ভুল সিঙ্ক পাসফ্রেজ। সিঙ্ক করা ক্রেডেনশিয়াল ডিক্রিপ্ট করা যায়নি।",
|
||||
"Email books straight to your library": "ইমেইলের মাধ্যমে সরাসরি বই আপনার লাইব্রেরিতে পাঠান",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "অ্যাটাচমেন্ট এবং নিবন্ধগুলি আপনার ব্যক্তিগত Readest ঠিকানায় ফরওয়ার্ড করুন। Plus, Pro এবং Lifetime প্ল্যানে উপলব্ধ।",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"Purge all reading data": "সমস্ত পড়ার ডেটা পরিষ্কার করুন",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "এটি স্থায়ীভাবে পড়ার অগ্রগতি, নোট এবং বুকমার্ক মুছে ফেলে। এটি পূর্বাবস্থায় ফেরানো যাবে না।",
|
||||
"Also erase reading progress, notes, and bookmarks.": "পড়ার অগ্রগতি, নোট এবং বুকমার্কও মুছে ফেলে।",
|
||||
"Applies to the Library": "লাইব্রেরিতে প্রযোজ্য",
|
||||
"Applies to the Reader": "রিডারে প্রযোজ্য"
|
||||
"Background Image (Library)": "ব্যাকগ্রাউন্ড ছবি (লাইব্রেরি)",
|
||||
"Background Image (Reader)": "ব্যাকগ্রাউন্ড ছবি (রিডার)"
|
||||
}
|
||||
|
||||
@@ -461,6 +461,7 @@
|
||||
"Sync Strategy": "སྤྲི་དོན་འབྱུང་ཁུངས།",
|
||||
"Ask on conflict": "འབྱུང་ཁུངས་འདེམས་པ་བྱས་ནས་བརྗེ་བ།",
|
||||
"Always use latest": "དེ་ལས་འབྱུང་ཁུངས་འདེམས་པ་བྱས་ནས་བརྗེ་བ།",
|
||||
"Send and receive": "གཏོང་བ་དང་ལེན་པ།",
|
||||
"Send changes only": "འབྱུང་ཁུངས་འདེམས་པ་བྱས་ནས་བརྗེ་བ།",
|
||||
"Receive changes only": "འབྱུང་ཁུངས་འདེམས་པ་བྱས་ནས་བརྗེ་བ།",
|
||||
"Checksum Method": "ཡིག་སྣེ་འབྱུང་ཁུངས།",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "མཉམ་སྦྲེལ་གསང་ཨང་བརྗེད་སོང་། གསང་སྦས་བྱས་པའི་ཁོངས་གཙང་འཕྱག་བྱས་ཟིན།",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "ལག་འཁྱེར་མཉམ་སྦྲེལ་དང་གཙང་སྦྲ་ཁོ་ན། ཀློག་སྐབས་ཀྱི་རང་འགུལ་མཉམ་སྦྲེལ་འདིར་ཐོ་འགོད་མི་བྱེད།",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV རིམ་པ་ཟུང་འབྲེལ་ནས་དཔེ་ཆ་{{n}}་སུབ་དགོས་སམ?\n\nའདིས་རྒྱང་རིང་གི་ཡིག་ཆ་ཁོ་ན་སུབ་པ་ཡིན། ཁྱེད་ཀྱི་ས་གནས་དཔེ་མཛོད་ལ་གནོད་མི་འགྱུར། སུབ་པ་འདི་ཕྱིར་ལོག་མི་ཐུབ། རིམ་པ་ཟུང་འབྲེལ་གྱི་ཟིན་བྲིས་གཏན་ནས་མེད་པར་འགྱུར།",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "དཔེ་ཆའི་ཡིག་ཆ་ཡར་འགོད་ལ་ཁོ་ན་གནོད་ཀྱི། ཀློག་འཐུས་དང་ཕབ་ལེན་རྟག་ཏུ་མཉམ་སྦྲེལ་འགྱུར།",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "དཔེ་ཆའི་ཡིག་ཆ་ཁྱེད་ཀྱི་སྒྲིག་ཆས་གཞན་པར་ཡར་འགོད་བྱེད།",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "མཉམ་སྦྲེལ་གསང་ཨང་ནོར་འདུག། མཉམ་སྦྲེལ་བྱས་པའི་ངོ་སྤྲོད་ཀྱི་གསང་སྒྲིག་འགྲོལ་མ་ཐུབ།",
|
||||
"Email books straight to your library": "གློག་འཕྲིན་གྱིས་དཔེ་ཆ་ཁྱེད་ཀྱི་དཔེ་མཛོད་དུ་ཐད་ཀར་སྐུར།",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "མཉམ་སྦྱར་དང་ཡིག་རྩོམ་ཁྱེད་ཀྱི་སྒེར་གྱི་ Readest ས་གནས་སུ་གཏོང་། Plus, Pro, Lifetime འཆར་གཞི་ལ་ཐོབ་པ།",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"Purge all reading data": "ཀློག་པའི་གཞི་གྲངས་ཡོངས་གཙང་སེལ།",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "འདིས་ཀློག་པའི་ཡར་འཕེལ་དང་། ཟིན་བྲིས། དཔེ་རྟགས་བཅས་གཏན་དུ་སུབ་ངེས་ཡིན། ཕྱིར་ལྡོག་བྱེད་མི་ཐུབ།",
|
||||
"Also erase reading progress, notes, and bookmarks.": "ཀློག་པའི་ཡར་འཕེལ་དང་། ཟིན་བྲིས། དཔེ་རྟགས་བཅས་ཀྱང་སུབ་པ།",
|
||||
"Applies to the Library": "དེབ་མཛོད་ལ་འཇུག་པ།",
|
||||
"Applies to the Reader": "ཀློག་ངོས་ལ་འཇུག་པ།"
|
||||
"Background Image (Library)": "གནས་སྟངས་ཀྱི་རི་མོ། (དེབ་མཛོད།)",
|
||||
"Background Image (Reader)": "གནས་སྟངས་ཀྱི་རི་མོ། (ཀློག་ངོས།)"
|
||||
}
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
"Sync Strategy": "Sync-Strategie",
|
||||
"Ask on conflict": "Bei Konflikten fragen",
|
||||
"Always use latest": "Immer die neueste Version verwenden",
|
||||
"Send and receive": "Senden und empfangen",
|
||||
"Send changes only": "Nur Änderungen senden",
|
||||
"Receive changes only": "Nur Änderungen empfangen",
|
||||
"Checksum Method": "Prüfziffernverfahren",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Sync-Passphrase vergessen. Alle verschlüsselten Felder gelöscht.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Nur manuelle Synchronisationen und Aufräumvorgänge. Automatische Synchronisationen beim Lesen werden hier nicht protokolliert.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "{{n}} Buch/Bücher vom WebDAV-Server löschen?\n\nDamit werden nur die Remote-Dateien entfernt; Ihre lokale Bibliothek bleibt unverändert. Das Löschen kann nicht rückgängig gemacht werden. Die Bytes auf dem Server sind dauerhaft verloren.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Betrifft nur das Hochladen von Buchdateien. Lesefortschritt und Downloads werden immer synchronisiert.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Lädt Buchdateien auf Ihre anderen Geräte hoch.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Falsche Sync-Passphrase. Synchronisierte Anmeldedaten konnten nicht entschlüsselt werden.",
|
||||
"Email books straight to your library": "Bücher direkt per E-Mail in Ihre Bibliothek senden",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Leiten Sie Anhänge und Artikel an Ihre private Readest-Adresse weiter. Verfügbar in den Plus-, Pro- und Lifetime-Tarifen.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Gilt für die Bibliothek",
|
||||
"Applies to the Reader": "Gilt für die Leseansicht"
|
||||
"Background Image (Library)": "Hintergrundbild (Bibliothek)",
|
||||
"Background Image (Reader)": "Hintergrundbild (Leseansicht)"
|
||||
}
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
"Sync Strategy": "Στρατηγική συγχρονισμού",
|
||||
"Ask on conflict": "Ρώτησε σε περίπτωση σύγκρουσης",
|
||||
"Always use latest": "Χρησιμοποίησε πάντα την τελευταία έκδοση",
|
||||
"Send and receive": "Αποστολή και λήψη",
|
||||
"Send changes only": "Αποστολή μόνο αλλαγών",
|
||||
"Receive changes only": "Λήψη μόνο αλλαγών",
|
||||
"Checksum Method": "Μέθοδος ελέγχου",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Η συνθηματική φράση συγχρονισμού λησμονήθηκε. Όλα τα κρυπτογραφημένα πεδία διαγράφηκαν.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Μόνο χειροκίνητοι συγχρονισμοί και εκκαθαρίσεις. Οι αυτόματοι συγχρονισμοί κατά την ανάγνωση δεν καταγράφονται εδώ.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Διαγραφή {{n}} βιβλίων από τον διακομιστή WebDAV;\n\nΑυτό αφαιρεί μόνο τα απομακρυσμένα αρχεία· η τοπική σας βιβλιοθήκη παραμένει ανέπαφη. Η διαγραφή είναι μη αναστρέψιμη. Τα δεδομένα στον διακομιστή θα χαθούν οριστικά.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Επηρεάζει μόνο τη μεταφόρτωση αρχείων βιβλίων. Η πρόοδος ανάγνωσης και οι λήψεις συγχρονίζονται πάντα.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Μεταφορτώνει αρχεία βιβλίων στις άλλες συσκευές σας.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Λανθασμένη συνθηματική φράση συγχρονισμού. Δεν ήταν δυνατή η αποκρυπτογράφηση των συγχρονισμένων διαπιστευτηρίων.",
|
||||
"Email books straight to your library": "Στείλτε βιβλία απευθείας στη βιβλιοθήκη σας μέσω email",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Προωθήστε συνημμένα και άρθρα στην ιδιωτική σας διεύθυνση Readest. Διαθέσιμο στα πλάνα Plus, Pro και Lifetime.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"Purge all reading data": "Εκκαθάριση όλων των δεδομένων ανάγνωσης",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Αυτό διαγράφει οριστικά την πρόοδο ανάγνωσης, τις σημειώσεις και τους σελιδοδείκτες. Δεν είναι δυνατή η αναίρεση.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Διαγράφει επίσης την πρόοδο ανάγνωσης, τις σημειώσεις και τους σελιδοδείκτες.",
|
||||
"Applies to the Library": "Ισχύει για τη βιβλιοθήκη",
|
||||
"Applies to the Reader": "Ισχύει για την προβολή ανάγνωσης"
|
||||
"Background Image (Library)": "Εικόνα φόντου (Βιβλιοθήκη)",
|
||||
"Background Image (Reader)": "Εικόνα φόντου (Προβολή ανάγνωσης)"
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
"Sync Strategy": "Estrategia de sincronización",
|
||||
"Ask on conflict": "Preguntar en caso de conflicto",
|
||||
"Always use latest": "Usar siempre el más reciente",
|
||||
"Send and receive": "Enviar y recibir",
|
||||
"Send changes only": "Solo enviar cambios",
|
||||
"Receive changes only": "Solo recibir cambios",
|
||||
"Checksum Method": "Método de identificación",
|
||||
@@ -1631,8 +1632,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Frase de paso de sincronización olvidada. Se borraron todos los campos cifrados.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Solo sincronizaciones manuales y limpiezas. Las sincronizaciones automáticas durante la lectura no se registran aquí.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "¿Eliminar {{n}} libro(s) del servidor WebDAV?\n\nEsto solo elimina los archivos remotos; tu biblioteca local no se verá afectada. La eliminación no se puede deshacer. Los bytes en el servidor desaparecerán permanentemente.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Solo afecta a la subida de archivos de libros. El progreso de lectura y las descargas siempre se sincronizan.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Sube los archivos de libros a tus otros dispositivos.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Frase de paso de sincronización incorrecta. No se pudieron descifrar las credenciales sincronizadas.",
|
||||
"Email books straight to your library": "Envía libros por correo directamente a tu biblioteca",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Reenvía archivos adjuntos y artículos a tu dirección privada de Readest. Disponible en los planes Plus, Pro y Lifetime.",
|
||||
@@ -1822,6 +1823,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Se aplica a la biblioteca",
|
||||
"Applies to the Reader": "Se aplica al lector"
|
||||
"Background Image (Library)": "Imagen de fondo (Biblioteca)",
|
||||
"Background Image (Reader)": "Imagen de fondo (Lector)"
|
||||
}
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
"Sync Strategy": "استراتژی همگامسازی",
|
||||
"Ask on conflict": "پرسش هنگام تداخل",
|
||||
"Always use latest": "همیشه از آخرین استفاده شود",
|
||||
"Send and receive": "ارسال و دریافت",
|
||||
"Send changes only": "فقط ارسال تغییرات",
|
||||
"Receive changes only": "فقط دریافت تغییرات",
|
||||
"Checksum Method": "روش Checksum",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "عبارت عبور همگامسازی فراموش شد. تمام فیلدهای رمزگذاریشده پاک شدند.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "فقط همگامسازیهای دستی و پاکسازیها. همگامسازیهای خودکار هنگام مطالعه اینجا ثبت نمیشوند.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "{{n}} کتاب از سرور WebDAV حذف شود؟\n\nاین فقط فایلهای راهدور را حذف میکند؛ کتابخانه محلی شما دستنخورده میماند. حذف غیرقابل بازگشت است. دادههای روی سرور برای همیشه از بین میرود.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "فقط بر بارگذاری فایلهای کتاب تأثیر میگذارد. پیشرفت مطالعه و دانلودها همیشه همگام میشوند.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "فایلهای کتاب را به دستگاههای دیگر شما بارگذاری میکند.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "عبارت عبور همگامسازی نادرست است. اعتبارنامههای همگامشده قابل رمزگشایی نبودند.",
|
||||
"Email books straight to your library": "کتابها را مستقیماً به کتابخانهتان ایمیل کنید",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "پیوستها و مقالات را به آدرس خصوصی Readest خود ارسال کنید. در پلنهای Plus، Pro و Lifetime در دسترس است.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"Purge all reading data": "پاکسازی همه دادههای مطالعه",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "این کار وضعیت مطالعه، یادداشتها و نشانکها را برای همیشه پاک میکند. این عمل قابل بازگشت نیست.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "همچنین وضعیت مطالعه، یادداشتها و نشانکها را پاک میکند.",
|
||||
"Applies to the Library": "برای کتابخانه اعمال میشود",
|
||||
"Applies to the Reader": "برای صفحه مطالعه اعمال میشود"
|
||||
"Background Image (Library)": "تصویر پسزمینه (کتابخانه)",
|
||||
"Background Image (Reader)": "تصویر پسزمینه (صفحه مطالعه)"
|
||||
}
|
||||
|
||||
@@ -467,6 +467,7 @@
|
||||
"Sync Strategy": "Stratégie de synchronisation",
|
||||
"Ask on conflict": "Demander en cas de conflit",
|
||||
"Always use latest": "Toujours utiliser la dernière version",
|
||||
"Send and receive": "Envoyer et recevoir",
|
||||
"Send changes only": "Envoyer uniquement les modifications",
|
||||
"Receive changes only": "Recevoir uniquement les modifications",
|
||||
"Checksum Method": "Méthode de somme de contrôle",
|
||||
@@ -1631,8 +1632,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Phrase secrète de synchronisation oubliée. Tous les champs chiffrés ont été effacés.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Synchronisations manuelles et nettoyages uniquement. Les synchronisations automatiques pendant la lecture ne sont pas enregistrées ici.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Supprimer {{n}} livre(s) du serveur WebDAV ?\n\nCela ne supprime que les fichiers distants ; votre bibliothèque locale n'est pas affectée. La suppression est irréversible. Les octets sur le serveur seront définitivement perdus.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Affecte uniquement le téléversement des fichiers de livres. La progression de lecture et les téléchargements sont toujours synchronisés.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Téléverse les fichiers de livres vers vos autres appareils.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Phrase secrète de synchronisation incorrecte. Les identifiants synchronisés n'ont pas pu être déchiffrés.",
|
||||
"Email books straight to your library": "Envoyez des livres par e-mail directement dans votre bibliothèque",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Transférez les pièces jointes et les articles vers votre adresse Readest privée. Disponible avec les forfaits Plus, Pro et Lifetime.",
|
||||
@@ -1822,6 +1823,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "S’applique à la bibliothèque",
|
||||
"Applies to the Reader": "S’applique à la vue de lecture"
|
||||
"Background Image (Library)": "Image de Fond (Bibliothèque)",
|
||||
"Background Image (Reader)": "Image de Fond (Vue de lecture)"
|
||||
}
|
||||
|
||||
@@ -423,6 +423,7 @@
|
||||
"Sync Strategy": "אסטרטגיית סנכרון",
|
||||
"Ask on conflict": "שאל בעת קונפליקט",
|
||||
"Always use latest": "תמיד השתמש בהכי חדש",
|
||||
"Send and receive": "שליחה וקבלה",
|
||||
"Send changes only": "שלח שינויים בלבד",
|
||||
"Receive changes only": "קבל שינויים בלבד",
|
||||
"Checksum Method": "שיטת סיכום ביקורת (Checksum)",
|
||||
@@ -1631,8 +1632,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "משפט הסיסמה לסנכרון נשכח. כל השדות המוצפנים נמחקו.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "רק סנכרונים ידניים וניקויים. סנכרונים אוטומטיים בזמן קריאה אינם נרשמים כאן.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "למחוק {{n}} ספרים משרת ה-WebDAV?\n\nפעולה זו מסירה רק את הקבצים המרוחקים; הספרייה המקומית שלך אינה מושפעת. לא ניתן לבטל את המחיקה. הבייטים בשרת ייעלמו לתמיד.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "משפיע רק על העלאת קובצי ספרים. התקדמות הקריאה וההורדות תמיד מסונכרנות.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "מעלה את קובצי הספרים למכשירים האחרים שלך.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "משפט סיסמה לסנכרון שגוי. לא ניתן היה לפענח את פרטי הכניסה המסונכרנים.",
|
||||
"Email books straight to your library": "שלח ספרים ישירות לספרייה שלך באמצעות אימייל",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "העבר קבצים מצורפים ומאמרים לכתובת Readest הפרטית שלך. זמין בתוכניות Plus, Pro ו-Lifetime.",
|
||||
@@ -1822,6 +1823,6 @@
|
||||
"Purge all reading data": "נקה את כל נתוני הקריאה",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "פעולה זו מוחקת לצמיתות את התקדמות הקריאה, ההערות והסימניות. לא ניתן לבטל פעולה זו.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "מוחק גם את התקדמות הקריאה, ההערות והסימניות.",
|
||||
"Applies to the Library": "חל על הספרייה",
|
||||
"Applies to the Reader": "חל על מצב הקריאה"
|
||||
"Background Image (Library)": "תמונת רקע (ספרייה)",
|
||||
"Background Image (Reader)": "תמונת רקע (מצב קריאה)"
|
||||
}
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
"Sync Strategy": "सिंक रणनीति",
|
||||
"Ask on conflict": "संघर्ष पर पूछें",
|
||||
"Always use latest": "हमेशा नवीनतम का उपयोग करें",
|
||||
"Send and receive": "भेजें और प्राप्त करें",
|
||||
"Send changes only": "केवल परिवर्तन भेजें",
|
||||
"Receive changes only": "केवल परिवर्तन प्राप्त करें",
|
||||
"Checksum Method": "चेकसम विधि",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "सिंक पासफ़्रेज़ भुलाया गया। सभी एन्क्रिप्ट किए गए फ़ील्ड साफ़ कर दिए गए।",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "केवल मैन्युअल सिंक और सफाई। पढ़ते समय स्वचालित सिंक यहाँ लॉग नहीं किए जाते।",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV सर्वर से {{n}} किताब(ें) हटाएं?\n\nयह केवल रिमोट फ़ाइलें हटाता है; आपकी स्थानीय लाइब्रेरी अप्रभावित रहती है। हटाना पूर्ववत नहीं किया जा सकता। सर्वर पर डेटा हमेशा के लिए चला जाएगा।",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "केवल पुस्तक फ़ाइलें अपलोड करने को प्रभावित करता है। पढ़ने की प्रगति और डाउनलोड हमेशा सिंक होते हैं।",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "पुस्तक फ़ाइलें आपके अन्य उपकरणों पर अपलोड करता है।",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "गलत सिंक पासफ़्रेज़। सिंक की गई क्रेडेंशियल्स को डिक्रिप्ट नहीं किया जा सका।",
|
||||
"Email books straight to your library": "अपनी लाइब्रेरी में सीधे ईमेल से किताबें भेजें",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "अनुलग्नक और लेख अपने निजी Readest पते पर अग्रेषित करें। Plus, Pro और Lifetime प्लान में उपलब्ध।",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"Purge all reading data": "सभी पढ़ने का डेटा साफ़ करें",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "यह पढ़ने की प्रगति, नोट्स और बुकमार्क को स्थायी रूप से मिटा देता है। इसे पूर्ववत नहीं किया जा सकता।",
|
||||
"Also erase reading progress, notes, and bookmarks.": "पढ़ने की प्रगति, नोट्स और बुकमार्क भी मिटा देता है।",
|
||||
"Applies to the Library": "लाइब्रेरी पर लागू होता है",
|
||||
"Applies to the Reader": "रीडर पर लागू होता है"
|
||||
"Background Image (Library)": "पृष्ठभूमि छवि (लाइब्रेरी)",
|
||||
"Background Image (Reader)": "पृष्ठभूमि छवि (रीडर)"
|
||||
}
|
||||
|
||||
@@ -469,6 +469,7 @@
|
||||
"Sync Strategy": "Szinkronizálási stratégia",
|
||||
"Ask on conflict": "Kérdezzen ütközéskor",
|
||||
"Always use latest": "Mindig a legújabbat használja",
|
||||
"Send and receive": "Küldés és fogadás",
|
||||
"Send changes only": "Csak módosítások küldése",
|
||||
"Receive changes only": "Csak módosítások fogadása",
|
||||
"Checksum Method": "Ellenőrzőösszeg-módszer",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "A szinkronizálási jelmondat törölve. Minden titkosított mező törölve.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Csak kézi szinkronizálások és takarítások. Az olvasás közbeni automatikus szinkronizálások itt nem szerepelnek.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Törli a(z) {{n}} könyvet a WebDAV kiszolgálóról?\n\nEz csak a távoli fájlokat törli; a helyi könyvtárát nem érinti. A törlés nem vonható vissza. A kiszolgálón lévő adatok véglegesen eltűnnek.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Csak a könyvfájlok feltöltését érinti. Az olvasási folyamat és a letöltések mindig szinkronizálódnak.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Feltölti a könyvfájlokat a többi eszközére.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Hibás szinkronizálási jelmondat. A szinkronizált hitelesítő adatokat nem sikerült visszafejteni.",
|
||||
"Email books straight to your library": "Küldjön könyveket közvetlenül e-mailben a könyvtárába",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Továbbítsa a mellékleteket és cikkeket a privát Readest-címére. Elérhető a Plus, Pro és Lifetime csomagokban.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "A könyvtárra vonatkozik",
|
||||
"Applies to the Reader": "Az olvasónézetre vonatkozik"
|
||||
"Background Image (Library)": "Háttérkép (Könyvtár)",
|
||||
"Background Image (Reader)": "Háttérkép (Olvasónézet)"
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@
|
||||
"Sync Strategy": "Strategi Sinkronisasi",
|
||||
"Ask on conflict": "Tanya saat terjadi konflik",
|
||||
"Always use latest": "Selalu gunakan yang terbaru",
|
||||
"Send and receive": "Kirim dan terima",
|
||||
"Send changes only": "Kirim perubahan saja",
|
||||
"Receive changes only": "Terima perubahan saja",
|
||||
"Checksum Method": "Metode Checksum",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Frasa sandi sinkronisasi dilupakan. Semua bidang terenkripsi dihapus.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Hanya sinkronisasi manual dan pembersihan. Sinkronisasi otomatis saat membaca tidak dicatat di sini.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Hapus {{n}} buku dari server WebDAV?\n\nIni hanya menghapus file jarak jauh; perpustakaan lokal Anda tidak terpengaruh. Penghapusan tidak dapat dibatalkan. Data di server akan hilang permanen.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Hanya memengaruhi unggahan file buku. Kemajuan baca dan unduhan selalu disinkronkan.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Mengunggah file buku ke perangkat Anda yang lain.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Frasa sandi sinkronisasi salah. Kredensial yang disinkronkan tidak dapat didekripsi.",
|
||||
"Email books straight to your library": "Kirim buku langsung ke perpustakaan Anda melalui email",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Teruskan lampiran dan artikel ke alamat Readest pribadi Anda. Tersedia di paket Plus, Pro, dan Lifetime.",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Berlaku untuk Perpustakaan",
|
||||
"Applies to the Reader": "Berlaku untuk tampilan baca"
|
||||
"Background Image (Library)": "Gambar Latar Belakang (Perpustakaan)",
|
||||
"Background Image (Reader)": "Gambar Latar Belakang (Tampilan Baca)"
|
||||
}
|
||||
|
||||
@@ -467,6 +467,7 @@
|
||||
"Sync Strategy": "Strategia di Sincronizzazione",
|
||||
"Ask on conflict": "Chiedi in caso di conflitto",
|
||||
"Always use latest": "Usa sempre l'ultima versione",
|
||||
"Send and receive": "Invia e ricevi",
|
||||
"Send changes only": "Invia solo le modifiche",
|
||||
"Receive changes only": "Ricevi solo le modifiche",
|
||||
"Checksum Method": "Metodo di Controllo",
|
||||
@@ -1631,8 +1632,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Passphrase di sincronizzazione dimenticata. Tutti i campi cifrati sono stati cancellati.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Solo sincronizzazioni manuali e pulizie. Le sincronizzazioni automatiche durante la lettura non vengono registrate qui.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Eliminare {{n}} libro/i dal server WebDAV?\n\nQuesto rimuove solo i file remoti; la tua libreria locale non è interessata. L'eliminazione non può essere annullata. I byte sul server saranno persi per sempre.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Influisce solo sul caricamento dei file dei libri. L'avanzamento di lettura e i download sono sempre sincronizzati.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Carica i file dei libri sugli altri tuoi dispositivi.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Passphrase di sincronizzazione errata. Impossibile decifrare le credenziali sincronizzate.",
|
||||
"Email books straight to your library": "Invia i libri direttamente alla tua libreria via email",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Inoltra allegati e articoli al tuo indirizzo Readest privato. Disponibile nei piani Plus, Pro e Lifetime.",
|
||||
@@ -1822,6 +1823,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Si applica alla libreria",
|
||||
"Applies to the Reader": "Si applica alla vista di lettura"
|
||||
"Background Image (Library)": "Immagine di sfondo (Libreria)",
|
||||
"Background Image (Reader)": "Immagine di sfondo (Vista di lettura)"
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@
|
||||
"Sync Strategy": "同期戦略",
|
||||
"Ask on conflict": "競合時に確認",
|
||||
"Always use latest": "最新を常に使用",
|
||||
"Send and receive": "送信と受信",
|
||||
"Send changes only": "変更のみを送信",
|
||||
"Receive changes only": "変更のみを受信",
|
||||
"Checksum Method": "チェックサム方式",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "同期パスフレーズを忘却しました。すべての暗号化フィールドがクリアされました。",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "手動同期とクリーンアップのみ。読書中の自動同期はここには記録されません。",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV サーバーから {{n}} 冊を削除しますか?\n\nこの操作はリモートファイルのみを削除します。ローカルライブラリには影響しません。削除は元に戻せません。サーバー上のデータは完全に失われます。",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "書籍ファイルのアップロードのみに影響します。読書の進捗とダウンロードは常に同期されます。",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "書籍ファイルを他のデバイスにアップロードします。",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "同期パスフレーズが正しくありません。同期された認証情報を復号できませんでした。",
|
||||
"Email books straight to your library": "本をメールで直接ライブラリに送信",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "添付ファイルや記事をあなた専用の Readest アドレスに転送できます。Plus、Pro、Lifetime プランで利用可能。",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"Purge all reading data": "すべての読書データを消去",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "読書進捗、メモ、ブックマークが完全に消去されます。この操作は元に戻せません。",
|
||||
"Also erase reading progress, notes, and bookmarks.": "読書進捗、メモ、ブックマークも消去します。",
|
||||
"Applies to the Library": "ライブラリに適用されます",
|
||||
"Applies to the Reader": "リーダーに適用されます"
|
||||
"Background Image (Library)": "背景画像(ライブラリ)",
|
||||
"Background Image (Reader)": "背景画像(リーダー)"
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@
|
||||
"Sync Strategy": "동기화 전략",
|
||||
"Ask on conflict": "충돌 시 묻기",
|
||||
"Always use latest": "항상 최신 버전 사용",
|
||||
"Send and receive": "전송 및 수신",
|
||||
"Send changes only": "변경 사항만 전송",
|
||||
"Receive changes only": "변경 사항만 수신",
|
||||
"Checksum Method": "체크섬 방법",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "동기화 암호구를 잊었습니다. 모든 암호화된 필드가 지워졌습니다.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "수동 동기화 및 정리만 표시됩니다. 읽는 중에 자동으로 수행된 동기화는 여기에 기록되지 않습니다.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV 서버에서 {{n}}권을 삭제하시겠습니까?\n\n이 작업은 원격 파일만 제거합니다; 로컬 라이브러리에는 영향을 주지 않습니다. 삭제는 취소할 수 없습니다. 서버의 데이터는 영구히 사라집니다.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "책 파일 업로드에만 영향을 줍니다. 읽기 진행도와 다운로드는 항상 동기화됩니다.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "책 파일을 다른 기기로 업로드합니다.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "동기화 암호구가 잘못되었습니다. 동기화된 자격 증명을 복호화할 수 없습니다.",
|
||||
"Email books straight to your library": "이메일로 책을 라이브러리에 바로 전송",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "첨부 파일과 기사를 개인 Readest 주소로 전달하세요. Plus, Pro, Lifetime 요금제에서 사용할 수 있습니다.",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"Purge all reading data": "모든 읽기 데이터 지우기",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "읽기 진행 상황, 메모, 북마크가 영구적으로 지워집니다. 이 작업은 되돌릴 수 없습니다.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "읽기 진행 상황, 메모, 북마크도 함께 지웁니다.",
|
||||
"Applies to the Library": "라이브러리에 적용됩니다",
|
||||
"Applies to the Reader": "리더에 적용됩니다"
|
||||
"Background Image (Library)": "배경 이미지 (라이브러리)",
|
||||
"Background Image (Reader)": "배경 이미지 (리더)"
|
||||
}
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
"Sync Strategy": "Strategi Segerak",
|
||||
"Ask on conflict": "Tanya jika konflik",
|
||||
"Always use latest": "Sentiasa guna terkini",
|
||||
"Send and receive": "Hantar dan terima",
|
||||
"Send changes only": "Hantar perubahan sahaja",
|
||||
"Receive changes only": "Terima perubahan sahaja",
|
||||
"Checksum Method": "Kaedah Semak Jumlah",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Frasa kata laluan penyegerakan dilupakan. Semua medan yang disulitkan dibersihkan.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Hanya penyegerakan manual dan pembersihan. Penyegerakan automatik semasa membaca tidak dilog di sini.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Padam {{n}} buah buku dari pelayan WebDAV?\n\nIni hanya membuang fail jauh; perpustakaan tempatan anda tidak terjejas. Pemadaman tidak boleh dibatalkan. Bait di pelayan akan hilang selamanya.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Hanya mempengaruhi muat naik fail buku. Kemajuan bacaan dan muat turun sentiasa disegerakkan.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Memuat naik fail buku ke peranti anda yang lain.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Frasa kata laluan penyegerakan salah. Bukti kelayakan yang disegerakkan tidak dapat dinyahsulit.",
|
||||
"Email books straight to your library": "E-mel buku terus ke perpustakaan anda",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Majukan lampiran dan artikel ke alamat Readest peribadi anda. Tersedia pada pelan Plus, Pro dan Lifetime.",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Digunakan pada Perpustakaan",
|
||||
"Applies to the Reader": "Digunakan pada paparan bacaan"
|
||||
"Background Image (Library)": "Imej Latar Belakang (Perpustakaan)",
|
||||
"Background Image (Reader)": "Imej Latar Belakang (Paparan Bacaan)"
|
||||
}
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
"Sync Strategy": "Synchronisatiestrategie",
|
||||
"Ask on conflict": "Vraag bij conflict",
|
||||
"Always use latest": "Altijd de nieuwste gebruiken",
|
||||
"Send and receive": "Verzenden en ontvangen",
|
||||
"Send changes only": "Verzend alleen wijzigingen",
|
||||
"Receive changes only": "Ontvang alleen wijzigingen",
|
||||
"Checksum Method": "Checksum-methode",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Sync-wachtwoordzin vergeten. Alle versleutelde velden gewist.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Alleen handmatige synchronisaties en opschoonacties. Automatische synchronisaties tijdens het lezen worden hier niet vastgelegd.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "{{n}} boek(en) van WebDAV-server verwijderen?\n\nDit verwijdert alleen de externe bestanden; je lokale bibliotheek wordt niet beïnvloed. Verwijderen kan niet ongedaan worden gemaakt. De bytes op de server zijn permanent verloren.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Heeft alleen invloed op het uploaden van boekbestanden. Leesvoortgang en downloads worden altijd gesynchroniseerd.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Uploadt boekbestanden naar uw andere apparaten.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Verkeerde sync-wachtwoordzin. Gesynchroniseerde inloggegevens konden niet worden ontsleuteld.",
|
||||
"Email books straight to your library": "Mail boeken rechtstreeks naar je bibliotheek",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Stuur bijlagen en artikelen door naar je privé Readest-adres. Beschikbaar in de Plus-, Pro- en Lifetime-abonnementen.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Geldt voor de bibliotheek",
|
||||
"Applies to the Reader": "Geldt voor de leesweergave"
|
||||
"Background Image (Library)": "Achtergrondafbeelding (Bibliotheek)",
|
||||
"Background Image (Reader)": "Achtergrondafbeelding (Leesweergave)"
|
||||
}
|
||||
|
||||
@@ -471,6 +471,7 @@
|
||||
"Sync Strategy": "Strategia synchronizacji",
|
||||
"Ask on conflict": "Pytaj w przypadku konfliktu",
|
||||
"Always use latest": "Zawsze używaj najnowszej",
|
||||
"Send and receive": "Wysyłanie i odbieranie",
|
||||
"Send changes only": "Wyślij tylko zmiany",
|
||||
"Receive changes only": "Odbierz tylko zmiany",
|
||||
"Checksum Method": "Metoda sumy kontrolnej",
|
||||
@@ -1661,8 +1662,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Zapomniano hasło synchronizacji. Wszystkie zaszyfrowane pola wyczyszczone.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Tylko ręczne synchronizacje i porządkowanie. Automatyczne synchronizacje podczas czytania nie są tu rejestrowane.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Usunąć {{n}} książek z serwera WebDAV?\n\nUsuwa to tylko zdalne pliki; lokalna biblioteka pozostaje nienaruszona. Usunięcia nie można cofnąć. Bajty na serwerze zostaną trwale utracone.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Wpływa tylko na wysyłanie plików książek. Postęp czytania i pobierania są zawsze synchronizowane.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Przesyła pliki książek na Twoje inne urządzenia.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Nieprawidłowe hasło synchronizacji. Nie udało się odszyfrować zsynchronizowanych poświadczeń.",
|
||||
"Email books straight to your library": "Wysyłaj książki e-mailem prosto do biblioteki",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Przekazuj załączniki i artykuły na swój prywatny adres Readest. Dostępne w planach Plus, Pro i Lifetime.",
|
||||
@@ -1855,6 +1856,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Dotyczy biblioteki",
|
||||
"Applies to the Reader": "Dotyczy widoku czytania"
|
||||
"Background Image (Library)": "Obraz tła (Biblioteka)",
|
||||
"Background Image (Reader)": "Obraz tła (Widok czytania)"
|
||||
}
|
||||
|
||||
@@ -533,6 +533,7 @@
|
||||
"Sync Strategy": "Estratégia de sincronização",
|
||||
"Ask on conflict": "Perguntar em caso de conflito",
|
||||
"Always use latest": "Sempre usar o mais recente",
|
||||
"Send and receive": "Enviar e receber",
|
||||
"Send changes only": "Enviar apenas alterações",
|
||||
"Receive changes only": "Receber apenas alterações",
|
||||
"Checksum Method": "Método de verificação",
|
||||
@@ -1631,8 +1632,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Frase-senha de sincronização esquecida. Todos os campos criptografados foram limpos.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Apenas sincronizações manuais e limpezas. As sincronizações automáticas durante a leitura não são registradas aqui.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Excluir {{n}} livro(s) do servidor WebDAV?\n\nIsso apenas remove os arquivos remotos; sua biblioteca local não é afetada. A exclusão não pode ser desfeita. Os bytes no servidor desaparecerão permanentemente.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Afeta apenas o envio de arquivos de livros. O progresso de leitura e os downloads são sempre sincronizados.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Envia os arquivos de livros para os seus outros dispositivos.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Frase-senha de sincronização incorreta. Não foi possível descriptografar as credenciais sincronizadas.",
|
||||
"Email books straight to your library": "Envie livros por e-mail direto para sua biblioteca",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Encaminhe anexos e artigos para seu endereço Readest privado. Disponível nos planos Plus, Pro e Lifetime.",
|
||||
@@ -1822,6 +1823,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Aplica-se à biblioteca",
|
||||
"Applies to the Reader": "Aplica-se à vista de leitura"
|
||||
"Background Image (Library)": "Imagem de fundo (Biblioteca)",
|
||||
"Background Image (Reader)": "Imagem de fundo (Vista de leitura)"
|
||||
}
|
||||
|
||||
@@ -467,6 +467,7 @@
|
||||
"Sync Strategy": "Estratégia de Sincronização",
|
||||
"Ask on conflict": "Perguntar em caso de conflito",
|
||||
"Always use latest": "Sempre usar o mais recente",
|
||||
"Send and receive": "Enviar e receber",
|
||||
"Send changes only": "Enviar apenas alterações",
|
||||
"Receive changes only": "Receber apenas alterações",
|
||||
"Checksum Method": "Método de Verificação",
|
||||
@@ -1631,8 +1632,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Frase-passe de sincronização esquecida. Todos os campos encriptados foram limpos.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Apenas sincronizações manuais e limpezas. As sincronizações automáticas durante a leitura não são registadas aqui.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Eliminar {{n}} livro(s) do servidor WebDAV?\n\nIsto apenas remove os ficheiros remotos; a sua biblioteca local não é afetada. A eliminação não pode ser anulada. Os bytes no servidor desaparecerão permanentemente.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Afeta apenas o envio de ficheiros de livros. O progresso de leitura e os descarregamentos são sempre sincronizados.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Envia os ficheiros de livros para os seus outros dispositivos.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Frase-passe de sincronização incorreta. Não foi possível desencriptar as credenciais sincronizadas.",
|
||||
"Email books straight to your library": "Envie livros por e-mail diretamente para a sua biblioteca",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Encaminhe anexos e artigos para o seu endereço Readest privado. Disponível nos planos Plus, Pro e Lifetime.",
|
||||
@@ -1822,6 +1823,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Aplica-se à biblioteca",
|
||||
"Applies to the Reader": "Aplica-se à vista de leitura"
|
||||
"Background Image (Library)": "Imagem de Fundo (Biblioteca)",
|
||||
"Background Image (Reader)": "Imagem de Fundo (Vista de leitura)"
|
||||
}
|
||||
|
||||
@@ -461,6 +461,7 @@
|
||||
"Sync Strategy": "Strategie de sincronizare",
|
||||
"Ask on conflict": "Întreabă în caz de conflict",
|
||||
"Always use latest": "Folosește întotdeauna cel mai recent",
|
||||
"Send and receive": "Trimite și primește",
|
||||
"Send changes only": "Trimite doar modificările",
|
||||
"Receive changes only": "Primește doar modificările",
|
||||
"Checksum Method": "Metoda sumei de control",
|
||||
@@ -1631,8 +1632,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Parola de sincronizare uitată. Toate câmpurile criptate au fost șterse.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Doar sincronizări manuale și curățări. Sincronizările automate în timpul citirii nu sunt înregistrate aici.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Ștergi {{n}} carte/cărți de pe serverul WebDAV?\n\nAceasta elimină doar fișierele de la distanță; biblioteca locală nu este afectată. Ștergerea nu poate fi anulată. Datele de pe server vor dispărea definitiv.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Afectează doar încărcarea fișierelor de carte. Progresul lecturii și descărcările se sincronizează întotdeauna.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Încarcă fișierele de carte pe celelalte dispozitive ale tale.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Parolă de sincronizare incorectă. Acreditările sincronizate nu au putut fi decriptate.",
|
||||
"Email books straight to your library": "Trimite cărți prin e-mail direct în biblioteca ta",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Redirecționează atașamente și articole către adresa ta Readest privată. Disponibil în planurile Plus, Pro și Lifetime.",
|
||||
@@ -1822,6 +1823,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Se aplică bibliotecii",
|
||||
"Applies to the Reader": "Se aplică vizualizării de lectură"
|
||||
"Background Image (Library)": "Imagine de fundal (Bibliotecă)",
|
||||
"Background Image (Reader)": "Imagine de fundal (Vizualizare de lectură)"
|
||||
}
|
||||
|
||||
@@ -471,6 +471,7 @@
|
||||
"Sync Strategy": "Стратегия синхронизации",
|
||||
"Ask on conflict": "Спрашивать при конфликте",
|
||||
"Always use latest": "Всегда использовать последнюю",
|
||||
"Send and receive": "Отправлять и получать",
|
||||
"Send changes only": "Отправлять только изменения",
|
||||
"Receive changes only": "Получать только изменения",
|
||||
"Checksum Method": "Метод контрольной суммы",
|
||||
@@ -1661,8 +1662,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Парольная фраза синхронизации забыта. Все зашифрованные поля очищены.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Только ручные синхронизации и очистки. Автоматические синхронизации во время чтения здесь не отображаются.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Удалить {{n}} книг с сервера WebDAV?\n\nЭто удалит только удалённые файлы; ваша локальная библиотека не пострадает. Удаление невозможно отменить. Данные на сервере исчезнут навсегда.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Влияет только на отправку файлов книг. Прогресс чтения и загрузки всегда синхронизируются.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Загружает файлы книг на ваши другие устройства.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Неверная парольная фраза синхронизации. Не удалось расшифровать синхронизированные данные.",
|
||||
"Email books straight to your library": "Отправляйте книги по электронной почте прямо в библиотеку",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Пересылайте вложения и статьи на ваш личный адрес Readest. Доступно в тарифах Plus, Pro и Lifetime.",
|
||||
@@ -1855,6 +1856,6 @@
|
||||
"Purge all reading data": "Очистить все данные чтения",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Это безвозвратно удалит прогресс чтения, заметки и закладки. Это действие нельзя отменить.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Также удаляет прогресс чтения, заметки и закладки.",
|
||||
"Applies to the Library": "Применяется к библиотеке",
|
||||
"Applies to the Reader": "Применяется к режиму чтения"
|
||||
"Background Image (Library)": "Фоновое изображение (Библиотека)",
|
||||
"Background Image (Reader)": "Фоновое изображение (Режим чтения)"
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"Sync Strategy": "සමමුහුර්ත උපාය",
|
||||
"Ask on conflict": "ගැටුමේදී විමසන්න",
|
||||
"Always use latest": "සෑම විටම නවතම භාවිතා කරන්න",
|
||||
"Send and receive": "යැවීම සහ ලැබීම",
|
||||
"Send changes only": "වෙනස්කම් පමණක් යවන්න",
|
||||
"Receive changes only": "වෙනස්කම් පමණක් ලබන්න",
|
||||
"Checksum Method": "පරීක්ෂණ ක්රමය",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "සමමුහුර්ත මුරපදය අමතක කරන ලදී. සියලුම සංකේතාංකන ක්ෂේත්ර හිස් කරන ලදී.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "අතින් සමමුහුර්තකරණ සහ පිරිසිදු කිරීම් පමණක්. කියවීමේදී ස්වයංක්රීය සමමුහුර්තකරණ මෙහි සටහන් නොවේ.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV සේවාදායකයෙන් පොත් {{n}}ක් මකන්න ද?\n\nමෙය දුරස්ථ ගොනු පමණක් ඉවත් කරයි; ඔබේ දේශීය පුස්තකාලය බලපාන්නේ නැත. මැකීම අහෝසි කළ නොහැක. සේවාදායකයේ දත්ත සදහටම නැති වේ.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "පොත් ගොනු උඩුගත කිරීමට පමණක් බලපායි. කියවීමේ ප්රගතිය සහ බාගත කිරීම් සැම විටම සමමුහුර්ත වේ.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "පොත් ගොනු ඔබගේ අනෙක් උපාංගවලට උඩුගත කරයි.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "වැරදි සමමුහුර්ත මුරපදය. සමමුහුර්ත අක්තපත්ර විකේතනය කළ නොහැකි විය.",
|
||||
"Email books straight to your library": "ඊමේල් මගින් ඔබේ පුස්තකාලයට කෙලින්ම පොත් යවන්න",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "ඇමුණුම් සහ ලිපි ඔබේ පෞද්ගලික Readest ලිපිනය වෙත ඉදිරියට යවන්න. Plus, Pro සහ Lifetime සැලසුම් වල ලබා ගත හැක.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"Purge all reading data": "සියලු කියවීම් දත්ත ඉවත් කරන්න",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "මෙය කියවීමේ ප්රගතිය, සටහන් සහ පොත් සලකුණු ස්ථිරවම මකා දමයි. මෙය අහෝසි කළ නොහැක.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "කියවීමේ ප්රගතිය, සටහන් සහ පොත් සලකුණු ද මකා දමයි.",
|
||||
"Applies to the Library": "පුස්තකාලයට අදාළ වේ",
|
||||
"Applies to the Reader": "කියවීමේ දසුනට අදාළ වේ"
|
||||
"Background Image (Library)": "පසුබිම් රූපය (පුස්තකාලය)",
|
||||
"Background Image (Reader)": "පසුබිම් රූපය (කියවීමේ දසුන)"
|
||||
}
|
||||
|
||||
@@ -439,6 +439,7 @@
|
||||
"Sync Strategy": "Strategija sinhronizacije",
|
||||
"Ask on conflict": "Vprašaj ob sporu",
|
||||
"Always use latest": "Vedno uporabi najnovejše",
|
||||
"Send and receive": "Pošiljanje in prejemanje",
|
||||
"Send changes only": "Pošlji samo spremembe",
|
||||
"Receive changes only": "Prejmi samo spremembe",
|
||||
"Checksum Method": "Metoda kontrolne vsote",
|
||||
@@ -1661,8 +1662,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Sinhronizacijska gesla pozabljena. Vsa šifrirana polja so počiščena.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Samo ročne sinhronizacije in čiščenja. Samodejne sinhronizacije med branjem se tu ne beležijo.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Izbrišem {{n}} knjig s strežnika WebDAV?\n\nTo odstrani samo oddaljene datoteke; vaša lokalna knjižnica ostane nedotaknjena. Izbrisa ni mogoče razveljaviti. Biti na strežniku bodo trajno izgubljeni.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Vpliva samo na nalaganje datotek knjig. Bralni napredek in prenosi se vedno sinhronizirajo.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Naloži datoteke knjig v vaše druge naprave.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Napačno geslo sinhronizacije. Sinhroniziranih poverilnic ni bilo mogoče dešifrirati.",
|
||||
"Email books straight to your library": "Knjige po e-pošti pošljite naravnost v knjižnico",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Posredujte priponke in članke na svoj zasebni Readest naslov. Na voljo v paketih Plus, Pro in Lifetime.",
|
||||
@@ -1855,6 +1856,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Velja za knjižnico",
|
||||
"Applies to the Reader": "Velja za bralni pogled"
|
||||
"Background Image (Library)": "Slikovno ozadje (Knjižnica)",
|
||||
"Background Image (Reader)": "Slikovno ozadje (Bralni pogled)"
|
||||
}
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
"Sync Strategy": "Synkstrategi",
|
||||
"Ask on conflict": "Fråga vid konflikt",
|
||||
"Always use latest": "Använd alltid senaste",
|
||||
"Send and receive": "Skicka och ta emot",
|
||||
"Send changes only": "Skicka endast ändringar",
|
||||
"Receive changes only": "Ta endast emot ändringar",
|
||||
"Checksum Method": "Kontrollsummemetod",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Synklösenfras glömd. Alla krypterade fält rensade.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Endast manuella synkroniseringar och rensningar. Automatiska synkroniseringar under läsning loggas inte här.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Ta bort {{n}} bok/böcker från WebDAV-servern?\n\nDetta tar bara bort fjärrfiler; ditt lokala bibliotek påverkas inte. Borttagningen kan inte ångras. Data på servern försvinner permanent.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Påverkar bara uppladdning av bokfiler. Läsförlopp och nedladdningar synkroniseras alltid.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Laddar upp bokfiler till dina andra enheter.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Fel synklösenfras. Synkroniserade autentiseringsuppgifter kunde inte dekrypteras.",
|
||||
"Email books straight to your library": "E-posta böcker direkt till ditt bibliotek",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Vidarebefordra bilagor och artiklar till din privata Readest-adress. Tillgänglig i Plus-, Pro- och Lifetime-abonnemangen.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Gäller biblioteket",
|
||||
"Applies to the Reader": "Gäller läsvyn"
|
||||
"Background Image (Library)": "Bakgrundsbild (Bibliotek)",
|
||||
"Background Image (Reader)": "Bakgrundsbild (Läsvy)"
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@
|
||||
"Sync Strategy": "ஒத்திசைவு உத்தி",
|
||||
"Ask on conflict": "முரண்பாட்டில் கேட்கவும்",
|
||||
"Always use latest": "எப்போதும் சமீபத்தியதைப் பயன்படுத்தவும்",
|
||||
"Send and receive": "அனுப்புதல் மற்றும் பெறுதல்",
|
||||
"Send changes only": "மாற்றங்களை மட்டும் அனுப்பவும்",
|
||||
"Receive changes only": "மாற்றங்களை மட்டும் பெறவும்",
|
||||
"Checksum Method": "சரிபார்ப்பு முறை",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "ஒத்திசைவு கடவுச்சொற்றொடர் மறக்கப்பட்டது. அனைத்து குறியாக்கப்பட்ட புலங்களும் அழிக்கப்பட்டன.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "கைமுறை ஒத்திசைவுகள் மற்றும் சுத்திகரிப்புகள் மட்டுமே. வாசிக்கும்போது தானியங்கி ஒத்திசைவுகள் இங்கு பதிவாகாது.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV சேவையகத்திலிருந்து {{n}} புத்தகம்(ங்கள்) நீக்க வேண்டுமா?\n\nஇது தொலைதூர கோப்புகளை மட்டுமே நீக்கும்; உங்கள் உள்ளூர் நூலகம் பாதிக்கப்படாது. நீக்கலை மீட்க முடியாது. சேவையகத்தில் உள்ள தரவு நிரந்தரமாக மறையும்.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "புத்தக கோப்புகள் பதிவேற்றத்தை மட்டுமே பாதிக்கும். வாசிப்பு முன்னேற்றமும் பதிவிறக்கங்களும் எப்போதும் ஒத்திசைகின்றன.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "புத்தக கோப்புகளை உங்கள் பிற சாதனங்களுக்கு பதிவேற்றுகிறது.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "தவறான ஒத்திசைவு கடவுச்சொற்றொடர். ஒத்திசைக்கப்பட்ட சான்றுகளை மறைகுறியாக்க முடியவில்லை.",
|
||||
"Email books straight to your library": "புத்தகங்களை மின்னஞ்சல் வழியாக நேரடியாக உங்கள் நூலகத்திற்கு அனுப்பவும்",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "இணைப்புகள் மற்றும் கட்டுரைகளை உங்கள் தனிப்பட்ட Readest முகவரிக்கு முன்னனுப்பவும். Plus, Pro மற்றும் Lifetime திட்டங்களில் கிடைக்கும்.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"Purge all reading data": "அனைத்து வாசிப்புத் தரவையும் அழி",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "இது வாசிப்பு முன்னேற்றம், குறிப்புகள் மற்றும் புக்மார்க்குகளை நிரந்தரமாக அழிக்கும். இதை மீட்டெடுக்க முடியாது.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "வாசிப்பு முன்னேற்றம், குறிப்புகள் மற்றும் புக்மார்க்குகளையும் அழிக்கும்.",
|
||||
"Applies to the Library": "நூலகத்திற்குப் பொருந்தும்",
|
||||
"Applies to the Reader": "வாசிப்புப் பக்கத்திற்குப் பொருந்தும்"
|
||||
"Background Image (Library)": "பின்னணி படம் (நூலகம்)",
|
||||
"Background Image (Reader)": "பின்னணி படம் (வாசிப்புப் பக்கம்)"
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@
|
||||
"Sync Strategy": "กลยุทธ์การซิงค์",
|
||||
"Ask on conflict": "ถามเมื่อเกิดความขัดแย้ง",
|
||||
"Always use latest": "ใช้เวอร์ชันล่าสุดเสมอ",
|
||||
"Send and receive": "ส่งและรับ",
|
||||
"Send changes only": "ส่งการเปลี่ยนแปลงเท่านั้น",
|
||||
"Receive changes only": "รับการเปลี่ยนแปลงเท่านั้น",
|
||||
"Checksum Method": "วิธีการตรวจสอบความถูกต้อง",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "ลืมรหัสผ่านการซิงค์แล้ว ฟิลด์ที่เข้ารหัสทั้งหมดถูกล้าง",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "การซิงค์และล้างข้อมูลด้วยตนเองเท่านั้น การซิงค์อัตโนมัติระหว่างอ่านจะไม่ถูกบันทึกที่นี่",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "ลบหนังสือ {{n}} เล่มจากเซิร์ฟเวอร์ WebDAV?\n\nสิ่งนี้จะลบเฉพาะไฟล์ระยะไกล; คลังข้อมูลในเครื่องของคุณจะไม่ได้รับผลกระทบ การลบไม่สามารถย้อนกลับได้ ข้อมูลบนเซิร์ฟเวอร์จะหายไปอย่างถาวร",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "มีผลกับการอัปโหลดไฟล์หนังสือเท่านั้น ความคืบหน้าการอ่านและการดาวน์โหลดจะซิงค์เสมอ",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "อัปโหลดไฟล์หนังสือไปยังอุปกรณ์อื่นของคุณ",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "รหัสผ่านการซิงค์ไม่ถูกต้อง ไม่สามารถถอดรหัสข้อมูลรับรองที่ซิงค์ได้",
|
||||
"Email books straight to your library": "ส่งหนังสือทางอีเมลไปยังคลังของคุณโดยตรง",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "ส่งต่อไฟล์แนบและบทความไปยังที่อยู่ Readest ส่วนตัวของคุณ ใช้งานได้ในแผน Plus, Pro และ Lifetime",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"Purge all reading data": "ล้างข้อมูลการอ่านทั้งหมด",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "การดำเนินการนี้จะลบความคืบหน้าในการอ่าน บันทึก และบุ๊กมาร์กอย่างถาวร ไม่สามารถเลิกทำได้",
|
||||
"Also erase reading progress, notes, and bookmarks.": "ลบความคืบหน้าในการอ่าน บันทึก และบุ๊กมาร์กด้วย",
|
||||
"Applies to the Library": "ใช้กับคลังหนังสือ",
|
||||
"Applies to the Reader": "ใช้กับมุมมองการอ่าน"
|
||||
"Background Image (Library)": "ภาพพื้นหลัง (คลังหนังสือ)",
|
||||
"Background Image (Reader)": "ภาพพื้นหลัง (มุมมองการอ่าน)"
|
||||
}
|
||||
|
||||
@@ -463,6 +463,7 @@
|
||||
"Sync Strategy": "Senkronizasyon Stratejisi",
|
||||
"Ask on conflict": "Çatışmada Sor",
|
||||
"Always use latest": "Her Zaman En Sonunu Kullan",
|
||||
"Send and receive": "Gönder ve al",
|
||||
"Send changes only": "Sadece Değişiklikleri Gönder",
|
||||
"Receive changes only": "Sadece Değişiklikleri Al",
|
||||
"Checksum Method": "Kontrol Toplamı Yöntemi",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Eşitleme parola tümcesi unutuldu. Tüm şifreli alanlar temizlendi.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Yalnızca manuel eşitlemeler ve temizlikler. Okuma sırasında otomatik eşitlemeler burada kaydedilmez.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV sunucusundan {{n}} kitap silinsin mi?\n\nBu yalnızca uzak dosyaları kaldırır; yerel kitaplığınız etkilenmez. Silme geri alınamaz. Sunucudaki veriler kalıcı olarak yok olur.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Yalnızca kitap dosyası yüklemeyi etkiler. Okuma ilerlemesi ve indirmeler her zaman eşitlenir.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Kitap dosyalarını diğer cihazlarınıza yükler.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Yanlış eşitleme parola tümcesi. Eşitlenmiş kimlik bilgileri çözülemedi.",
|
||||
"Email books straight to your library": "Kitapları e-postayla doğrudan kitaplığınıza gönderin",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Ekleri ve makaleleri özel Readest adresinize iletin. Plus, Pro ve Lifetime planlarında kullanılabilir.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Kütüphaneye uygulanır",
|
||||
"Applies to the Reader": "Okuma görünümüne uygulanır"
|
||||
"Background Image (Library)": "Arka Plan Görüntüsü (Kütüphane)",
|
||||
"Background Image (Reader)": "Arka Plan Görüntüsü (Okuma Görünümü)"
|
||||
}
|
||||
|
||||
@@ -471,6 +471,7 @@
|
||||
"Sync Strategy": "Стратегія синхронізації",
|
||||
"Ask on conflict": "Запитувати при конфлікті",
|
||||
"Always use latest": "Завжди використовувати найновішу",
|
||||
"Send and receive": "Надсилати й отримувати",
|
||||
"Send changes only": "Відправити тільки зміни",
|
||||
"Receive changes only": "Отримати тільки зміни",
|
||||
"Checksum Method": "Метод контролю суми",
|
||||
@@ -1661,8 +1662,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Парольну фразу синхронізації забуто. Усі зашифровані поля очищено.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Лише ручні синхронізації та очищення. Автоматичні синхронізації під час читання тут не записуються.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Видалити {{n}} книг із сервера WebDAV?\n\nЦе видалить лише віддалені файли; ваша локальна бібліотека не зміниться. Видалення неможливо скасувати. Дані на сервері зникнуть назавжди.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Впливає лише на вивантаження файлів книг. Прогрес читання й завантаження завжди синхронізуються.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Вивантажує файли книг на ваші інші пристрої.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Неправильна парольна фраза синхронізації. Не вдалося розшифрувати синхронізовані облікові дані.",
|
||||
"Email books straight to your library": "Надсилайте книги електронною поштою прямо в бібліотеку",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Пересилайте вкладення та статті на свою приватну адресу Readest. Доступно в планах Plus, Pro і Lifetime.",
|
||||
@@ -1855,6 +1856,6 @@
|
||||
"Purge all reading data": "Очистити всі дані читання",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "Це назавжди видалить проґрес читання, нотатки та закладки. Цю дію не можна скасувати.",
|
||||
"Also erase reading progress, notes, and bookmarks.": "Також видаляє проґрес читання, нотатки та закладки.",
|
||||
"Applies to the Library": "Застосовується до бібліотеки",
|
||||
"Applies to the Reader": "Застосовується до режиму читання"
|
||||
"Background Image (Library)": "Фонове зображення (Бібліотека)",
|
||||
"Background Image (Reader)": "Фонове зображення (Режим читання)"
|
||||
}
|
||||
|
||||
@@ -523,6 +523,7 @@
|
||||
"Sync Strategy": "Sinxronlash strategiyasi",
|
||||
"Ask on conflict": "Ziddiyatda soʻrash",
|
||||
"Always use latest": "Doimo eng songgisidan foydalanish",
|
||||
"Send and receive": "Yuborish va qabul qilish",
|
||||
"Send changes only": "Faqat oʻzgarishlarni yuborish",
|
||||
"Receive changes only": "Faqat oʻzgarishlarni qabul qilish",
|
||||
"Checksum Method": "Nazorat yigʻindisi usuli",
|
||||
@@ -1601,8 +1602,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Sinxronlash parol iborasi unutildi. Barcha shifrlangan maydonlar tozalandi.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Faqat qo'lda sinxronlashlar va tozalashlar. O'qish paytidagi avtomatik sinxronlashlar bu yerda qayd etilmaydi.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "WebDAV serveridan {{n}} ta kitob o'chirilsinmi?\n\nBu faqat masofaviy fayllarni o'chiradi; mahalliy kutubxonangiz ta'sirlanmaydi. O'chirishni bekor qilib bo'lmaydi. Serverdagi ma'lumotlar mangulikka yo'qoladi.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Faqat kitob fayllarini yuklashga ta'sir qiladi. O'qish jarayoni va yuklab olishlar har doim sinxronlanadi.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Kitob fayllarini boshqa qurilmalaringizga yuklaydi.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Noto'g'ri sinxronlash parol iborasi. Sinxronlangan hisob ma'lumotlarini parolini ochib bo'lmadi.",
|
||||
"Email books straight to your library": "Kitoblarni elektron pochta orqali to'g'ridan-to'g'ri kutubxonangizga yuboring",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Ilovalar va maqolalarni shaxsiy Readest manzilingizga yuboring. Plus, Pro va Lifetime tariflarida mavjud.",
|
||||
@@ -1789,6 +1790,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Kutubxonaga qoʻllanadi",
|
||||
"Applies to the Reader": "Oʻqish koʻrinishiga qoʻllanadi"
|
||||
"Background Image (Library)": "Fon rasmi (Kutubxona)",
|
||||
"Background Image (Reader)": "Fon rasmi (Oʻqish koʻrinishi)"
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@
|
||||
"Sync Strategy": "Chiến lược đồng bộ",
|
||||
"Ask on conflict": "Hỏi khi có xung đột",
|
||||
"Always use latest": "Luôn sử dụng phiên bản mới nhất",
|
||||
"Send and receive": "Gửi và nhận",
|
||||
"Send changes only": "Chỉ gửi thay đổi",
|
||||
"Receive changes only": "Chỉ nhận thay đổi",
|
||||
"Checksum Method": "Phương pháp kiểm tra",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "Đã quên cụm mật khẩu đồng bộ. Tất cả các trường được mã hóa đã bị xóa.",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "Chỉ đồng bộ thủ công và dọn dẹp. Các lần đồng bộ tự động khi đọc không được ghi tại đây.",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "Xóa {{n}} sách khỏi máy chủ WebDAV?\n\nThao tác này chỉ xóa các tệp từ xa; thư viện cục bộ của bạn không bị ảnh hưởng. Không thể hoàn tác. Dữ liệu trên máy chủ sẽ mất vĩnh viễn.",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "Chỉ ảnh hưởng đến việc tải lên tệp sách. Tiến độ đọc và tải xuống luôn được đồng bộ.",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "Tải lên tệp sách đến các thiết bị khác của bạn.",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "Cụm mật khẩu đồng bộ không đúng. Không thể giải mã thông tin xác thực đã đồng bộ.",
|
||||
"Email books straight to your library": "Gửi sách qua email thẳng đến thư viện của bạn",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "Chuyển tiếp tệp đính kèm và bài viết đến địa chỉ Readest riêng của bạn. Có sẵn trong các gói Plus, Pro và Lifetime.",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"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.",
|
||||
"Applies to the Library": "Áp dụng cho Thư viện",
|
||||
"Applies to the Reader": "Áp dụng cho trình đọc"
|
||||
"Background Image (Library)": "Ảnh nền (Thư viện)",
|
||||
"Background Image (Reader)": "Ảnh nền (Trình đọc)"
|
||||
}
|
||||
|
||||
@@ -460,6 +460,7 @@
|
||||
"Sync Strategy": "同步策略",
|
||||
"Ask on conflict": "发生冲突时询问",
|
||||
"Always use latest": "始终使用最新",
|
||||
"Send and receive": "发送和接收",
|
||||
"Send changes only": "仅发送更改",
|
||||
"Receive changes only": "仅接收更改",
|
||||
"Checksum Method": "校验和方法",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "已忘记同步密码短语。所有加密字段已清空。",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "仅显示手动同步与清理。阅读时的自动同步不在此记录。",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "从 WebDAV 服务器删除 {{n}} 本书?\n\n这只会移除远程文件;您的本地书库不受影响。删除无法撤销。服务器上的数据将永久消失。",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "仅影响书籍文件的上传。阅读进度和下载始终同步。",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "将书籍文件上传到您的其他设备。",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "同步密码短语错误。无法解密已同步的凭据。",
|
||||
"Email books straight to your library": "通过电子邮件直接将书籍发送到您的书库",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "将附件和文章转发到您的专属 Readest 地址。Plus、Pro 和 Lifetime 套餐可用。",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"Purge all reading data": "清除所有阅读数据",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "这将永久清除阅读进度、笔记和书签,且无法撤销。",
|
||||
"Also erase reading progress, notes, and bookmarks.": "同时清除阅读进度、笔记和书签。",
|
||||
"Applies to the Library": "应用于书库",
|
||||
"Applies to the Reader": "应用于阅读界面"
|
||||
"Background Image (Library)": "背景图片(书库)",
|
||||
"Background Image (Reader)": "背景图片(阅读界面)"
|
||||
}
|
||||
|
||||
@@ -459,6 +459,7 @@
|
||||
"Sync Strategy": "同步策略",
|
||||
"Ask on conflict": "發生衝突時詢問",
|
||||
"Always use latest": "始終使用最新",
|
||||
"Send and receive": "發送和接收",
|
||||
"Send changes only": "僅發送更改",
|
||||
"Receive changes only": "僅接收更改",
|
||||
"Checksum Method": "校驗和方法",
|
||||
@@ -1571,8 +1572,8 @@
|
||||
"Sync passphrase forgotten. All encrypted fields cleared.": "已忘記同步密碼短語。所有加密欄位已清空。",
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.": "僅顯示手動同步與清理。閱讀時的自動同步不在此記錄。",
|
||||
"Delete {{n}} book(s) from the WebDAV server?\n\nThis only removes the remote files; your local library is unaffected. The deletion cannot be undone. The bytes on the server will be permanently gone.": "從 WebDAV 伺服器刪除 {{n}} 本書?\n\n這只會移除遠端檔案;您的本機書庫不受影響。刪除無法復原。伺服器上的資料將永久消失。",
|
||||
"{{action}} {{n}} / {{total}} · {{title}}": "{{action}} {{n}} / {{total}} · {{title}}",
|
||||
"Only affects uploading book files. Reading progress and downloads always sync.": "僅影響書籍檔案的上傳。閱讀進度和下載始終同步。",
|
||||
"{{action}} {{n}} / {{total}}": "{{action}} {{n}} / {{total}}",
|
||||
"Uploads book files to your other devices.": "將書籍檔案上傳到您的其他裝置。",
|
||||
"Wrong sync passphrase. Synced credentials could not be decrypted.": "同步密碼短語錯誤。無法解密已同步的憑證。",
|
||||
"Email books straight to your library": "透過電子郵件直接將書籍傳送到您的書庫",
|
||||
"Forward attachments and articles to your private Readest address. Available on the Plus, Pro, and Lifetime plans.": "將附件和文章轉寄到您的專屬 Readest 地址。Plus、Pro 和 Lifetime 方案可用。",
|
||||
@@ -1756,6 +1757,6 @@
|
||||
"Purge all reading data": "清除所有閱讀資料",
|
||||
"This permanently erases reading progress, notes, and bookmarks. This cannot be undone.": "這將永久清除閱讀進度、筆記和書籤,且無法復原。",
|
||||
"Also erase reading progress, notes, and bookmarks.": "同時清除閱讀進度、筆記和書籤。",
|
||||
"Applies to the Library": "套用於書庫",
|
||||
"Applies to the Reader": "套用於閱讀介面"
|
||||
"Background Image (Library)": "背景圖片(書庫)",
|
||||
"Background Image (Reader)": "背景圖片(閱讀介面)"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { buildWebDAVConnectSettings } from '@/services/webdav/webdavConnectSettings';
|
||||
import type { WebDAVSettings, WebDAVSyncLogEntry } from '@/types/settings';
|
||||
import type { WebDAVSettings } from '@/types/settings';
|
||||
|
||||
describe('buildWebDAVConnectSettings', () => {
|
||||
test('applies form fields onto a blank previous state', () => {
|
||||
@@ -21,26 +21,8 @@ describe('buildWebDAVConnectSettings', () => {
|
||||
|
||||
test('preserves prior bookkeeping fields across reconnect', () => {
|
||||
// Simulates the disconnect → reconnect flow: the user previously
|
||||
// synced (deviceId minted, syncBooks toggled on, history populated),
|
||||
// disabled WebDAV, and is now reconnecting with the same credentials.
|
||||
const log: WebDAVSyncLogEntry[] = [
|
||||
{
|
||||
id: 'log-1',
|
||||
startedAt: 1_700_000_000_000,
|
||||
finishedAt: 1_700_000_001_500,
|
||||
status: 'success',
|
||||
trigger: 'manual',
|
||||
totalBooks: 3,
|
||||
booksDownloaded: 0,
|
||||
filesUploaded: 1,
|
||||
filesAlreadyInSync: 2,
|
||||
configsUploaded: 3,
|
||||
configsDownloaded: 0,
|
||||
coversUploaded: 0,
|
||||
failures: 0,
|
||||
summary: 'Sync complete',
|
||||
},
|
||||
];
|
||||
// synced (deviceId minted, syncBooks toggled on), disabled WebDAV,
|
||||
// and is now reconnecting with the same credentials.
|
||||
const previous: WebDAVSettings = {
|
||||
enabled: false,
|
||||
serverUrl: 'https://dav.example.com',
|
||||
@@ -53,7 +35,6 @@ describe('buildWebDAVConnectSettings', () => {
|
||||
strategy: 'send',
|
||||
deviceId: 'device-uuid-9f3c',
|
||||
lastSyncedAt: 1_700_000_001_500,
|
||||
syncLog: log,
|
||||
};
|
||||
|
||||
const next = buildWebDAVConnectSettings(previous, {
|
||||
@@ -73,7 +54,6 @@ describe('buildWebDAVConnectSettings', () => {
|
||||
expect(next.syncProgress).toBe(true);
|
||||
expect(next.syncNotes).toBe(true);
|
||||
expect(next.lastSyncedAt).toBe(1_700_000_001_500);
|
||||
expect(next.syncLog).toEqual(log);
|
||||
});
|
||||
|
||||
test('updates the credentials when the user reconnects to a different account', () => {
|
||||
|
||||
@@ -143,7 +143,7 @@ export const useWebDAVSync = (bookKey: string) => {
|
||||
// doesn't reflect interim writes by the prior call. Using the
|
||||
// closure here would let a second `updateLastSyncedAt` rebuild
|
||||
// the webdav object from a stale snapshot, clobbering whatever
|
||||
// the first call (or a sibling write like `syncLog` from the
|
||||
// the first call (or a sibling write like `syncBooks` from the
|
||||
// settings panel) just committed.
|
||||
const latest = useSettingsStore.getState().settings;
|
||||
const next = { ...latest, webdav: { ...latest.webdav, lastSyncedAt: ts } };
|
||||
|
||||
@@ -391,7 +391,9 @@ const ColorPanel: React.FC<SettingsPanelPanelProp> = ({ bookKey, onRegisterReset
|
||||
<BackgroundTextureSelector
|
||||
predefinedTextures={PREDEFINED_TEXTURES}
|
||||
customTextures={customTextures.filter((t) => !t.deletedAt)}
|
||||
scopeLabel={isLibraryContext ? _('Applies to the Library') : _('Applies to the Reader')}
|
||||
title={
|
||||
isLibraryContext ? _('Background Image (Library)') : _('Background Image (Reader)')
|
||||
}
|
||||
selectedTextureId={selectedTextureId}
|
||||
backgroundOpacity={backgroundOpacity}
|
||||
backgroundSize={backgroundSize}
|
||||
|
||||
@@ -15,8 +15,8 @@ interface Texture {
|
||||
interface BackgroundTextureSelectorProps {
|
||||
predefinedTextures: Texture[];
|
||||
customTextures: Texture[];
|
||||
/** Optional sublabel clarifying which page this texture applies to (#4743). */
|
||||
scopeLabel?: string;
|
||||
/** Section title, scoped to the page the texture applies to (#4743). */
|
||||
title: string;
|
||||
selectedTextureId: string;
|
||||
backgroundOpacity: number;
|
||||
backgroundSize: string;
|
||||
@@ -30,7 +30,7 @@ interface BackgroundTextureSelectorProps {
|
||||
const BackgroundTextureSelector: React.FC<BackgroundTextureSelectorProps> = ({
|
||||
predefinedTextures,
|
||||
customTextures,
|
||||
scopeLabel,
|
||||
title,
|
||||
selectedTextureId,
|
||||
backgroundOpacity,
|
||||
backgroundSize,
|
||||
@@ -47,8 +47,7 @@ const BackgroundTextureSelector: React.FC<BackgroundTextureSelectorProps> = ({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SectionTitle className={scopeLabel ? 'mb-1' : 'mb-2'}>{_('Background Image')}</SectionTitle>
|
||||
{scopeLabel && <p className='text-base-content/60 mb-2 text-xs'>{scopeLabel}</p>}
|
||||
<SectionTitle className='mb-2'>{title}</SectionTitle>
|
||||
<div className='mb-4 grid grid-cols-2 gap-4'>
|
||||
{allTextures.map((texture) => (
|
||||
// The swatch is a div (not a <button>) so the inner Delete
|
||||
|
||||
@@ -257,7 +257,7 @@ const SendToReadestForm: React.FC<SendToReadestFormProps> = ({ onBack }) => {
|
||||
<SectionTitle className='mb-2'>{_('Your inbound address')}</SectionTitle>
|
||||
<div className='card eink-bordered border-base-200 bg-base-100 divide-base-200 overflow-hidden border'>
|
||||
<div className='flex items-center gap-2 px-4 py-3'>
|
||||
<code className='min-w-0 flex-1 truncate text-sm'>{address}</code>
|
||||
<code className='line-clamp-2 min-w-0 flex-1 break-all text-sm'>{address}</code>
|
||||
{address && (
|
||||
<button
|
||||
type='button'
|
||||
@@ -320,7 +320,7 @@ const SendToReadestForm: React.FC<SendToReadestFormProps> = ({ onBack }) => {
|
||||
{senders.map((sender) => (
|
||||
<div key={sender.id} className='flex items-center gap-3 px-4 py-3'>
|
||||
<div className='flex min-w-0 flex-1 flex-col'>
|
||||
<SettingLabel>{sender.email}</SettingLabel>
|
||||
<code className='line-clamp-2 break-all text-sm'>{sender.email}</code>
|
||||
{sender.status === 'pending' && (
|
||||
<span className='text-warning text-[0.8em]'>{_('Pending approval')}</span>
|
||||
)}
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
import { WebDAVSyncLogEntry, WebDAVSyncLogStatus } from '@/types/settings';
|
||||
import { useTranslation, type TranslationFunc } from '@/hooks/useTranslation';
|
||||
import { BoxedList, SettingsRow } from '../primitives';
|
||||
|
||||
/**
|
||||
* Diagnostic surface for the most-recent ten WebDAV manual runs —
|
||||
* Sync now from the form plus batch cleanups (Delete from server)
|
||||
* issued from the WebDAV browser. Auto-syncs triggered while reading
|
||||
* are intentionally NOT logged here; they fire once per page-turn
|
||||
* and would drown out the manual signal users care about.
|
||||
*
|
||||
* Why a separate component (rather than inline JSX in WebDAVForm):
|
||||
* - Keeps the outer form file legible; the panel has its own state
|
||||
* model (which entry is expanded) that doesn't belong in the parent.
|
||||
* - Co-locates the per-entry rendering (counters, failure list,
|
||||
* duration) with the component that owns it. The parent only knows
|
||||
* about "the log" as a whole and how to clear it.
|
||||
*
|
||||
* Presentational: all persistence happens in the parent
|
||||
* (`appendSyncLogEntry` / `handleClearSyncLog`).
|
||||
*/
|
||||
export interface SyncHistoryPanelProps {
|
||||
entries: WebDAVSyncLogEntry[];
|
||||
onClear: () => void | Promise<void>;
|
||||
}
|
||||
|
||||
const SyncHistoryPanel: React.FC<SyncHistoryPanelProps> = ({ entries, onClear }) => {
|
||||
const _ = useTranslation();
|
||||
// Only one entry expanded at a time keeps the panel scannable on
|
||||
// mobile — multiple open rows can quickly push the disconnect button
|
||||
// off-screen. Set to null when no row is expanded.
|
||||
const [expandedId, setExpandedId] = useState<string | null>(null);
|
||||
|
||||
const hasEntries = entries.length > 0;
|
||||
|
||||
return (
|
||||
<BoxedList>
|
||||
<SettingsRow
|
||||
label={_('Sync History')}
|
||||
description={_(
|
||||
"Manual syncs and cleanups only. Automatic syncs while reading aren't logged here.",
|
||||
)}
|
||||
>
|
||||
{hasEntries ? (
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => onClear()}
|
||||
className='btn btn-ghost btn-sm h-8 min-h-8 px-2'
|
||||
title={_('Clear Sync History')}
|
||||
aria-label={_('Clear Sync History')}
|
||||
>
|
||||
{_('Clear')}
|
||||
</button>
|
||||
) : (
|
||||
<span className='text-base-content/50 text-xs'>{_('No manual syncs yet')}</span>
|
||||
)}
|
||||
</SettingsRow>
|
||||
{hasEntries && (
|
||||
<ul className='divide-base-200 divide-y'>
|
||||
{entries.map((entry) => {
|
||||
const isExpanded = expandedId === entry.id;
|
||||
return (
|
||||
<li key={entry.id} className='px-4 py-3'>
|
||||
<button
|
||||
type='button'
|
||||
onClick={() => setExpandedId(isExpanded ? null : entry.id)}
|
||||
className='group flex w-full items-center gap-3 text-left'
|
||||
aria-expanded={isExpanded}
|
||||
>
|
||||
<SyncStatusBadge status={entry.status} />
|
||||
{entry.kind === 'cleanup' && <SyncKindBadge />}
|
||||
<div className='flex min-w-0 flex-1 flex-col gap-0.5'>
|
||||
<span className='text-sm'>{formatSyncSummaryLine(entry, _)}</span>
|
||||
<span className='text-base-content/60 text-[0.75em]'>
|
||||
{formatSyncTimestamp(entry.startedAt, entry.finishedAt, _)}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className={clsx(
|
||||
'text-base-content/50 transition-transform',
|
||||
isExpanded && 'rotate-90',
|
||||
)}
|
||||
aria-hidden
|
||||
>
|
||||
›
|
||||
</span>
|
||||
</button>
|
||||
{isExpanded && <SyncHistoryDetails entry={entry} />}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
</BoxedList>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Coloured pill summarising an entry's status. We pick semantic
|
||||
* Tailwind utilities (success / warning / error) so the badge respects
|
||||
* the user's theme (eink, dark, light) without per-mode overrides.
|
||||
*/
|
||||
const SyncStatusBadge: React.FC<{ status: WebDAVSyncLogStatus }> = ({ status }) => {
|
||||
const _ = useTranslation();
|
||||
const map: Record<WebDAVSyncLogStatus, { label: string; className: string }> = {
|
||||
success: { label: _('OK'), className: 'bg-success/15 text-success' },
|
||||
partial: { label: _('Partial'), className: 'bg-warning/15 text-warning' },
|
||||
failure: { label: _('Failed'), className: 'bg-error/15 text-error' },
|
||||
};
|
||||
const { label, className } = map[status];
|
||||
return (
|
||||
<span
|
||||
className={clsx(
|
||||
'flex h-6 flex-shrink-0 items-center rounded px-2 text-[0.7rem] font-medium',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Secondary badge that flags non-sync runs (currently only batch
|
||||
* cleanups from the WebDAV browser). Sync entries don't get a kind
|
||||
* badge — the absence is the signal — so the row stays visually
|
||||
* unchanged for the common case. The cleanup variant uses a neutral
|
||||
* info colour rather than red/orange because the run already carries
|
||||
* its own status badge (success / partial / failed) right next to
|
||||
* it; piling more colour on would just shout.
|
||||
*/
|
||||
const SyncKindBadge: React.FC = () => {
|
||||
const _ = useTranslation();
|
||||
return (
|
||||
<span
|
||||
className={clsx(
|
||||
'flex h-6 flex-shrink-0 items-center rounded px-2 text-[0.7rem] font-medium',
|
||||
'bg-info/15 text-info',
|
||||
)}
|
||||
>
|
||||
{_('Cleanup')}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the one-line summary shown next to each history row's status
|
||||
* badge. We re-derive it from the structured counters (rather than
|
||||
* reusing the toast's `entry.summary`) so the text in the log stays
|
||||
* compact even when the original toast was multi-line.
|
||||
*/
|
||||
const formatSyncSummaryLine = (entry: WebDAVSyncLogEntry, _: TranslationFunc): string => {
|
||||
if (entry.status === 'failure') {
|
||||
return (
|
||||
entry.errorMessage || (entry.kind === 'cleanup' ? _('Cleanup failed') : _('Sync failed'))
|
||||
);
|
||||
}
|
||||
if (entry.kind === 'cleanup') {
|
||||
// Cleanup runs only have two interesting numbers: how many
|
||||
// server-side dirs got deleted and how many failed. None of the
|
||||
// sync counters apply, so build a dedicated summary rather than
|
||||
// running the cleanup entry through the upload/download formatter
|
||||
// and watching every clause come up zero.
|
||||
const parts: string[] = [];
|
||||
if ((entry.booksDeleted ?? 0) > 0) {
|
||||
parts.push(_('{{n}} deleted', { n: entry.booksDeleted ?? 0 }));
|
||||
}
|
||||
if (entry.failures > 0) {
|
||||
parts.push(_('{{n}} failed', { n: entry.failures }));
|
||||
}
|
||||
return parts.length > 0 ? parts.join(' · ') : _('Nothing deleted');
|
||||
}
|
||||
const parts: string[] = [];
|
||||
if (entry.booksDownloaded > 0) {
|
||||
parts.push(_('{{n}} downloaded', { n: entry.booksDownloaded }));
|
||||
}
|
||||
if (entry.filesUploaded > 0) {
|
||||
parts.push(_('{{n}} uploaded', { n: entry.filesUploaded }));
|
||||
}
|
||||
if (entry.configsUploaded > 0 || entry.configsDownloaded > 0) {
|
||||
parts.push(_('{{n}} progress', { n: entry.configsUploaded + entry.configsDownloaded }));
|
||||
}
|
||||
if (entry.failures > 0) {
|
||||
parts.push(_('{{n}} failed', { n: entry.failures }));
|
||||
}
|
||||
return parts.length > 0 ? parts.join(' · ') : _('Up to date');
|
||||
};
|
||||
|
||||
/**
|
||||
* "Mar 18, 14:32 · 4.2 s" — short locale-aware timestamp plus a
|
||||
* duration so users can spot abnormally slow runs at a glance.
|
||||
*/
|
||||
const formatSyncTimestamp = (startedAt: number, finishedAt: number, _: TranslationFunc): string => {
|
||||
const when = new Date(startedAt).toLocaleString(undefined, {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
const durMs = Math.max(0, finishedAt - startedAt);
|
||||
const dur = durMs >= 1000 ? `${(durMs / 1000).toFixed(1)} s` : `${durMs} ms`;
|
||||
return _('{{when}} · {{dur}}', { when, dur });
|
||||
};
|
||||
|
||||
/**
|
||||
* Expanded body of one history entry: the full counter grid plus the
|
||||
* per-book failure list when present. Counters that are zero are
|
||||
* suppressed so the grid only shows what actually happened — a
|
||||
* partial-failure row with three items is much easier to read than
|
||||
* the same row with seven zeroes interleaved.
|
||||
*/
|
||||
const SyncHistoryDetails: React.FC<{
|
||||
entry: WebDAVSyncLogEntry;
|
||||
}> = ({ entry }) => {
|
||||
const _ = useTranslation();
|
||||
// Counters are grouped semantically so the user can scan them at a
|
||||
// glance instead of treating eight numbers as a flat blob:
|
||||
// - "activity": work performed during this run
|
||||
// - "skipped": work that was deduped / no-op'd
|
||||
// - "outcome": totals + failure count for at-a-glance triage
|
||||
// Each group renders independently and is separated by a divider so
|
||||
// it's visually obvious that "Configs uploaded" and "Total books"
|
||||
// are different things — they previously sat side-by-side in a
|
||||
// single grid which read as one block.
|
||||
const groups: { label: string; value: number }[][] = [
|
||||
[
|
||||
{ label: _('Books downloaded'), value: entry.booksDownloaded },
|
||||
{ label: _('Files uploaded'), value: entry.filesUploaded },
|
||||
{ label: _('Configs uploaded'), value: entry.configsUploaded },
|
||||
{ label: _('Configs downloaded'), value: entry.configsDownloaded },
|
||||
{ label: _('Covers uploaded'), value: entry.coversUploaded },
|
||||
// Cleanup-specific counter. Suppressed by the zero-filter on
|
||||
// sync entries (which always set this to zero/undefined), so
|
||||
// it only shows up on cleanup runs without polluting the
|
||||
// common sync detail view.
|
||||
{ label: _('Books deleted'), value: entry.booksDeleted ?? 0 },
|
||||
],
|
||||
[{ label: _('Files in sync'), value: entry.filesAlreadyInSync }],
|
||||
[
|
||||
{ label: _('Failures'), value: entry.failures },
|
||||
{ label: _('Total books'), value: entry.totalBooks },
|
||||
],
|
||||
]
|
||||
// Suppress zero-only groups entirely so we don't render an empty
|
||||
// section + divider for a group whose every counter happens to be
|
||||
// zero this run (common: 'skipped' and 'outcome' rows on a quiet
|
||||
// sync). The within-group filter keeps individual zero entries out
|
||||
// of mixed groups.
|
||||
.map((group) => group.filter((c) => c.value > 0))
|
||||
.filter((group) => group.length > 0);
|
||||
|
||||
return (
|
||||
<div className='mt-3 flex flex-col gap-3 pl-9'>
|
||||
{groups.length > 0 && (
|
||||
// Six-column grid: each of the three semantic groups occupies
|
||||
// a (label-column, value-column) pair. Label columns flex with
|
||||
// available space and wrap naturally for long strings like
|
||||
// "Configs uploaded"; value columns are sized to content so
|
||||
// the numbers stay tightly packed against their labels. Border
|
||||
// dividers between every other column visually separate the
|
||||
// three groups; we draw them with `border-l` on columns 3 and
|
||||
// 5 rather than CSS `divide-x` because divide-x can't honour
|
||||
// the "skip every two columns" pattern.
|
||||
<div
|
||||
className={clsx(
|
||||
'border-base-200 grid rounded border',
|
||||
'gap-x-3 gap-y-2 px-3 py-2 text-xs',
|
||||
)}
|
||||
style={{
|
||||
gridTemplateColumns: 'minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr) auto',
|
||||
}}
|
||||
>
|
||||
{(() => {
|
||||
// All three columns share row count to keep the grid rows
|
||||
// aligned. Compute it once outside the per-group map so
|
||||
// each column sees the same value.
|
||||
const maxRows = Math.max(...groups.map((g) => g.length), 0);
|
||||
return [0, 1, 2].map((groupIdx) => {
|
||||
const group = groups[groupIdx] ?? [];
|
||||
const cells: React.ReactNode[] = [];
|
||||
for (let row = 0; row < maxRows; row++) {
|
||||
const c = group[row];
|
||||
cells.push(
|
||||
<div
|
||||
key={`l-${groupIdx}-${row}`}
|
||||
className={clsx(
|
||||
'text-base-content/60 leading-tight',
|
||||
// Group separator: every group except the first
|
||||
// gets a left border on its label column. The
|
||||
// negative left margin offsets the gap so the
|
||||
// line falls inside the gutter rather than
|
||||
// beside the text itself.
|
||||
groupIdx > 0 && 'border-base-200 -ml-3 border-l pl-3',
|
||||
)}
|
||||
>
|
||||
{c?.label ?? ''}
|
||||
</div>,
|
||||
);
|
||||
cells.push(
|
||||
<div key={`v-${groupIdx}-${row}`} className='text-end font-medium tabular-nums'>
|
||||
{c?.value ?? ''}
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
return cells;
|
||||
});
|
||||
})()}
|
||||
</div>
|
||||
)}
|
||||
{entry.errorMessage && (
|
||||
<div className='text-error/90 break-words text-xs'>
|
||||
<span className='text-base-content/60 mr-1'>{_('Error:')}</span>
|
||||
{entry.errorMessage}
|
||||
</div>
|
||||
)}
|
||||
{entry.failedBooks && entry.failedBooks.length > 0 && (
|
||||
<div className='flex flex-col gap-1'>
|
||||
<span className='text-base-content/60 text-xs'>{_('Failed books')}</span>
|
||||
<ul className='flex flex-col gap-1 text-xs'>
|
||||
{entry.failedBooks.map((f) => (
|
||||
<li key={f.hash} className='border-base-200 break-words rounded border px-2 py-1.5'>
|
||||
<div className='font-medium'>{f.title}</div>
|
||||
<div className='text-base-content/70 mt-0.5'>{f.reason}</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SyncHistoryPanel;
|
||||
@@ -29,8 +29,7 @@ import {
|
||||
} from '@/services/webdav/WebDAVClient';
|
||||
import { buildBasePath, WEBDAV_BOOKS_DIR } from '@/services/webdav/WebDAVPaths';
|
||||
import { deleteRemoteBookDir } from '@/services/webdav/WebDAVSync';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { WebDAVSettings, WebDAVSyncLogEntry, WebDAVSyncLogFailure } from '@/types/settings';
|
||||
import { WebDAVSettings } from '@/types/settings';
|
||||
import { Book } from '@/types/book';
|
||||
import { SettingLabel } from '../primitives';
|
||||
import {
|
||||
@@ -50,11 +49,9 @@ import {
|
||||
*/
|
||||
export interface WebDAVBrowsePaneProps {
|
||||
settings: WebDAVSettings;
|
||||
/** Persist a cleanup run into the parent's sync log when supplied. */
|
||||
onAppendSyncLogEntry?: (entry: WebDAVSyncLogEntry) => Promise<void> | void;
|
||||
}
|
||||
|
||||
const WebDAVBrowsePane: React.FC<WebDAVBrowsePaneProps> = ({ settings, onAppendSyncLogEntry }) => {
|
||||
const WebDAVBrowsePane: React.FC<WebDAVBrowsePaneProps> = ({ settings }) => {
|
||||
const _ = useTranslation();
|
||||
const { envConfig } = useEnv();
|
||||
const { user } = useAuth();
|
||||
@@ -191,7 +188,6 @@ const WebDAVBrowsePane: React.FC<WebDAVBrowsePaneProps> = ({ settings, onAppendS
|
||||
);
|
||||
if (!confirmed) return;
|
||||
|
||||
const startedAt = Date.now();
|
||||
let succeeded = 0;
|
||||
const failed: Array<{ hash: string; title: string; reason: string }> = [];
|
||||
let authFailed = false;
|
||||
@@ -242,23 +238,16 @@ const WebDAVBrowsePane: React.FC<WebDAVBrowsePaneProps> = ({ settings, onAppendS
|
||||
// listing in lock-step with the server, and a redundant reload
|
||||
// would briefly swap in the loading spinner — visible jump.
|
||||
|
||||
// One source of truth for the toast and the log entry.
|
||||
let toastType: 'info' | 'warning' | 'error';
|
||||
let message: string;
|
||||
let status: 'success' | 'partial' | 'failure';
|
||||
let errorMessage: string | undefined;
|
||||
if (authFailed) {
|
||||
toastType = 'error';
|
||||
status = 'failure';
|
||||
message = _('WebDAV authentication failed. Reconnect in Settings.');
|
||||
errorMessage = message;
|
||||
} else if (failed.length === 0) {
|
||||
toastType = 'info';
|
||||
status = 'success';
|
||||
message = _('Deleted {{n}} book(s) from server.', { n: succeeded });
|
||||
} else if (succeeded > 0) {
|
||||
toastType = 'warning';
|
||||
status = 'partial';
|
||||
message = _(
|
||||
'Deleted {{ok}} of {{total}} book(s) from server; {{n}} failed (first: "{{first}}").',
|
||||
{
|
||||
@@ -270,7 +259,6 @@ const WebDAVBrowsePane: React.FC<WebDAVBrowsePaneProps> = ({ settings, onAppendS
|
||||
);
|
||||
} else {
|
||||
toastType = 'warning';
|
||||
status = 'failure';
|
||||
message = _('Couldn\'t delete any of {{n}} book(s) from server (first: "{{first}}").', {
|
||||
n: failed.length,
|
||||
first: failed[0]?.title ?? '',
|
||||
@@ -281,43 +269,6 @@ const WebDAVBrowsePane: React.FC<WebDAVBrowsePaneProps> = ({ settings, onAppendS
|
||||
console.warn('[webdav cleanup] delete failures', failed);
|
||||
}
|
||||
eventDispatcher.dispatch('toast', { type: toastType, message });
|
||||
|
||||
// Persist into the shared sync log so cleanup runs are auditable
|
||||
// alongside Sync now. The 'cleanup' kind tag drives the panel's
|
||||
// badge and summary line; sync-only counters stay zero and the
|
||||
// panel's zero-suppress filter hides them.
|
||||
if (onAppendSyncLogEntry) {
|
||||
const failedBooks: WebDAVSyncLogFailure[] | undefined =
|
||||
failed.length > 0
|
||||
? failed.map((f) => ({ hash: f.hash, title: f.title, reason: f.reason }))
|
||||
: undefined;
|
||||
const entry: WebDAVSyncLogEntry = {
|
||||
id: uuidv4(),
|
||||
startedAt,
|
||||
finishedAt: Date.now(),
|
||||
kind: 'cleanup',
|
||||
status,
|
||||
trigger: 'manual',
|
||||
totalBooks: targets.length,
|
||||
booksDownloaded: 0,
|
||||
filesUploaded: 0,
|
||||
filesAlreadyInSync: 0,
|
||||
configsUploaded: 0,
|
||||
configsDownloaded: 0,
|
||||
coversUploaded: 0,
|
||||
booksDeleted: succeeded,
|
||||
failures: failed.length,
|
||||
summary: message,
|
||||
errorMessage,
|
||||
failedBooks,
|
||||
};
|
||||
// Fire-and-forget: a log-write failure shouldn't surface as a
|
||||
// second toast right after the cleanup result, the user has
|
||||
// already seen the outcome they care about.
|
||||
void Promise.resolve(onAppendSyncLogEntry(entry)).catch((e) =>
|
||||
console.warn('WD cleanup: failed to append sync log entry', e),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Drop stale paths from the selection whenever displayedEntries
|
||||
|
||||
@@ -22,12 +22,6 @@ import { type TranslationFunc } from '@/hooks/useTranslation';
|
||||
import { syncLibrary } from '@/services/webdav/WebDAVSync';
|
||||
import { buildWebDAVConnectSettings } from '@/services/webdav/webdavConnectSettings';
|
||||
import { getCoverFilename, getLocalBookFilename } from '@/utils/book';
|
||||
import {
|
||||
WEBDAV_SYNC_LOG_LIMIT,
|
||||
WebDAVSyncLogEntry,
|
||||
WebDAVSyncLogFailure,
|
||||
WebDAVSyncLogStatus,
|
||||
} from '@/types/settings';
|
||||
import SubPageHeader from '../SubPageHeader';
|
||||
import {
|
||||
BoxedList,
|
||||
@@ -36,7 +30,6 @@ import {
|
||||
SettingsSwitchRow,
|
||||
SettingsSelect,
|
||||
} from '../primitives';
|
||||
import SyncHistoryPanel from './SyncHistoryPanel';
|
||||
import WebDAVBrowsePane from './WebDAVBrowsePane';
|
||||
|
||||
interface WebDAVFormProps {
|
||||
@@ -136,6 +129,7 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
// server. See `webdavSyncStore.ts` for the design rationale.
|
||||
const isSyncing = useWebDAVSyncStore((s) => s.isSyncing);
|
||||
const syncProgressLabel = useWebDAVSyncStore((s) => s.progressLabel);
|
||||
const syncProgressDetail = useWebDAVSyncStore((s) => s.progressDetail);
|
||||
const beginSync = useWebDAVSyncStore((s) => s.beginSync);
|
||||
const updateProgress = useWebDAVSyncStore((s) => s.updateProgress);
|
||||
const endSync = useWebDAVSyncStore((s) => s.endSync);
|
||||
@@ -155,8 +149,8 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
}
|
||||
// Spread previous webdav state so a reconnect preserves bookkeeping
|
||||
// fields earned by prior use — deviceId, syncBooks, strategy,
|
||||
// syncProgress, syncNotes, lastSyncedAt, syncLog. Rotating deviceId
|
||||
// on reconnect would make this device look new to the cross-device
|
||||
// syncProgress, syncNotes, lastSyncedAt. Rotating deviceId on
|
||||
// reconnect would make this device look new to the cross-device
|
||||
// clobber check in `RemoteBookConfig.writerDeviceId`.
|
||||
const newSettings = {
|
||||
...settings,
|
||||
@@ -196,15 +190,14 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
// per session).
|
||||
//
|
||||
// IMPORTANT: read latest settings from the store (NOT the closure
|
||||
// variable) when computing `next`. `handleSyncNow` issues two
|
||||
// back-to-back persistWebdav calls — first `lastSyncedAt`, then
|
||||
// `syncLog`. The closure's `settings` was captured before either
|
||||
// write landed, so a closure-based merge would clobber the freshly-
|
||||
// written `lastSyncedAt` when the second call rebuilds the webdav
|
||||
// object from the stale snapshot. Symptom: the "Last synced" label
|
||||
// stays pinned to the previous value while the Sync History row
|
||||
// shows the up-to-date timestamp. Use `useSettingsStore.getState()`
|
||||
// so each call merges into whatever's currently committed.
|
||||
// variable) when computing `next`. Several persistWebdav calls can
|
||||
// land back-to-back — e.g. `handleSyncNow` writes `deviceId` up front
|
||||
// and `lastSyncedAt` when it finishes, and the user may flip a toggle
|
||||
// in between. The closure's `settings` was captured before those
|
||||
// writes, so a closure-based merge would rebuild the webdav object
|
||||
// from a stale snapshot and clobber a freshly-written field. Use
|
||||
// `useSettingsStore.getState()` so each call merges into whatever's
|
||||
// currently committed.
|
||||
const persistWebdav = async (patch: Partial<typeof stored>) => {
|
||||
const latest = useSettingsStore.getState().settings;
|
||||
const next = { ...latest, webdav: { ...latest.webdav, ...patch } };
|
||||
@@ -220,29 +213,6 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
await persistWebdav({ strategy: e.target.value as typeof stored.strategy });
|
||||
};
|
||||
|
||||
/**
|
||||
* Append a diagnostic entry to the bounded sync history.
|
||||
*
|
||||
* We deliberately re-read settings from the store at write time
|
||||
* (rather than closing over `stored`) so concurrent updates — e.g.
|
||||
* the user flips the syncBooks toggle while a Sync now is in flight
|
||||
* — don't clobber each other. The 10-entry cap matches
|
||||
* `WEBDAV_SYNC_LOG_LIMIT` and trims oldest-first; we keep the
|
||||
* persisted JSON small so settings.json round-trips on every app
|
||||
* start stay cheap.
|
||||
*/
|
||||
const appendSyncLogEntry = async (entry: WebDAVSyncLogEntry) => {
|
||||
const current = useSettingsStore.getState().settings.webdav?.syncLog ?? [];
|
||||
// Newest first — UI renders in array order, so unshift keeps the
|
||||
// freshest run at the top without reversing on every render.
|
||||
const next = [entry, ...current].slice(0, WEBDAV_SYNC_LOG_LIMIT);
|
||||
await persistWebdav({ syncLog: next });
|
||||
};
|
||||
|
||||
const handleClearSyncLog = async () => {
|
||||
await persistWebdav({ syncLog: [] });
|
||||
};
|
||||
|
||||
/**
|
||||
* Manual "Sync now" — push every book in the local library up to the
|
||||
* remote in a single sequential pass. We don't pull here; the per-
|
||||
@@ -286,11 +256,6 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
|
||||
beginSync(_('Syncing {{n}} / {{total}}', { n: 0, total: eligibleBooks.length }));
|
||||
|
||||
// Captured before the run begins so we can attribute startedAt
|
||||
// accurately even when the run fails in the catch block (the
|
||||
// pre-flight library load can take a moment on slow disks).
|
||||
const startedAt = Date.now();
|
||||
|
||||
try {
|
||||
const result = await syncLibrary(stored, eligibleBooks, {
|
||||
strategy: stored.strategy === 'prompt' ? 'silent' : stored.strategy,
|
||||
@@ -448,12 +413,8 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
onProgress: ({ book, index, total, action }) => {
|
||||
const actionStr = action === 'downloading' ? _('Downloading') : _('Uploading');
|
||||
updateProgress(
|
||||
_('{{action}} {{n}} / {{total}} · {{title}}', {
|
||||
action: actionStr,
|
||||
n: index + 1,
|
||||
total,
|
||||
title: book.title || book.hash.slice(0, 8),
|
||||
}),
|
||||
_('{{action}} {{n}} / {{total}}', { action: actionStr, n: index + 1, total }),
|
||||
book.title || book.hash.slice(0, 8),
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -508,64 +469,9 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
type: toastType,
|
||||
message: summary,
|
||||
});
|
||||
// Append a diagnostic entry to the persistent sync log. Status
|
||||
// mirrors the toast classification: warning toast → 'partial'
|
||||
// (some failures, some ok); info/success toast → 'success'. We
|
||||
// also collapse the per-book failure phase + reason into the
|
||||
// shape the UI expects (no internal type leakage into settings).
|
||||
const status: WebDAVSyncLogStatus = result.failures > 0 ? 'partial' : 'success';
|
||||
const failedBooks: WebDAVSyncLogFailure[] | undefined =
|
||||
result.failedBooks.length > 0
|
||||
? result.failedBooks.map((f) => ({
|
||||
hash: f.hash,
|
||||
title: f.title,
|
||||
reason: `[${f.phase}] ${f.reason}`,
|
||||
}))
|
||||
: undefined;
|
||||
const entry: WebDAVSyncLogEntry = {
|
||||
id: uuidv4(),
|
||||
startedAt,
|
||||
finishedAt: Date.now(),
|
||||
status,
|
||||
trigger: 'manual',
|
||||
totalBooks: result.totalBooks,
|
||||
booksDownloaded: result.booksDownloaded,
|
||||
filesUploaded: result.filesUploaded,
|
||||
filesAlreadyInSync: result.filesAlreadyInSync,
|
||||
configsUploaded: result.configsUploaded,
|
||||
configsDownloaded: result.configsDownloaded,
|
||||
coversUploaded: result.coversUploaded,
|
||||
failures: result.failures,
|
||||
summary,
|
||||
failedBooks,
|
||||
};
|
||||
await appendSyncLogEntry(entry);
|
||||
} catch (e) {
|
||||
const message = formatSyncError(_, e);
|
||||
eventDispatcher.dispatch('toast', { type: 'error', message });
|
||||
// Persist a "failure" entry so the user can show what went wrong
|
||||
// without rummaging through the dev console. We don't have a
|
||||
// SyncLibraryResult to draw counters from (the run aborted
|
||||
// before returning), so all the count fields stay zero except
|
||||
// totalBooks for context.
|
||||
const entry: WebDAVSyncLogEntry = {
|
||||
id: uuidv4(),
|
||||
startedAt,
|
||||
finishedAt: Date.now(),
|
||||
status: 'failure',
|
||||
trigger: 'manual',
|
||||
totalBooks: eligibleBooks.length,
|
||||
booksDownloaded: 0,
|
||||
filesUploaded: 0,
|
||||
filesAlreadyInSync: 0,
|
||||
configsUploaded: 0,
|
||||
configsDownloaded: 0,
|
||||
coversUploaded: 0,
|
||||
failures: 0,
|
||||
summary: message,
|
||||
errorMessage: e instanceof Error ? e.message : String(e),
|
||||
};
|
||||
await appendSyncLogEntry(entry);
|
||||
} finally {
|
||||
endSync();
|
||||
}
|
||||
@@ -595,9 +501,7 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
<BoxedList>
|
||||
<SettingsSwitchRow
|
||||
label={_('Upload Book Files')}
|
||||
description={_(
|
||||
'Only affects uploading book files. Reading progress and downloads always sync.',
|
||||
)}
|
||||
description={_('Uploads book files to your other devices.')}
|
||||
checked={stored.syncBooks ?? false}
|
||||
onChange={handleToggleSyncBooks}
|
||||
/>
|
||||
@@ -607,7 +511,7 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
onChange={handleStrategyChange}
|
||||
ariaLabel={_('Sync Strategy')}
|
||||
options={[
|
||||
{ value: 'silent', label: _('Always use latest') },
|
||||
{ value: 'silent', label: _('Send and receive') },
|
||||
{ value: 'send', label: _('Send changes only') },
|
||||
{ value: 'receive', label: _('Receive changes only') },
|
||||
]}
|
||||
@@ -623,6 +527,11 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
})
|
||||
: _('Never synced')
|
||||
}
|
||||
description={
|
||||
syncProgressDetail ? (
|
||||
<span className='line-clamp-1'>{syncProgressDetail}</span>
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
<button
|
||||
type='button'
|
||||
@@ -645,15 +554,7 @@ const WebDAVForm: React.FC<WebDAVFormProps> = ({ onBack }) => {
|
||||
</SettingsRow>
|
||||
</BoxedList>
|
||||
|
||||
{/* Sync history panel — diagnostic surface for users to
|
||||
screenshot when reporting issues. Collapsed by default to
|
||||
keep the page compact; opens to show the most-recent ten
|
||||
runs with full counters and per-book failures. We render
|
||||
even when the log is empty so users can find where it
|
||||
lives before their first run. */}
|
||||
<SyncHistoryPanel entries={stored.syncLog ?? []} onClear={handleClearSyncLog} />
|
||||
|
||||
<WebDAVBrowsePane settings={stored} onAppendSyncLogEntry={appendSyncLogEntry} />
|
||||
<WebDAVBrowsePane settings={stored} />
|
||||
|
||||
<div className='flex justify-end'>
|
||||
<button
|
||||
|
||||
@@ -676,19 +676,18 @@ export interface SyncLibraryOptions {
|
||||
* counters returned to the caller drive the final toast.
|
||||
*/
|
||||
/**
|
||||
* Reduce an arbitrary error to a short, single-line description suitable
|
||||
* for surfacing in the user-visible sync log.
|
||||
* Reduce an arbitrary error to a short, single-line description for the
|
||||
* per-book failure breakdown in the returned {@link SyncLibraryResult}.
|
||||
*
|
||||
* Goals:
|
||||
* - Strip stack traces and any embedded server XML so the persisted
|
||||
* `syncLog` in settings.json doesn't bloat (settings is read on every
|
||||
* app start, so size matters).
|
||||
* - Strip stack traces and any embedded server XML so each reason stays
|
||||
* a compact one-liner.
|
||||
* - Preserve the semantically useful bits — HTTP status, our own
|
||||
* `code` enum (`AUTH_FAILED`, `NOT_FOUND`, `NETWORK`) — because that
|
||||
* is what tells a user whether they should re-tap or fix their
|
||||
* credentials.
|
||||
* - Cap at 200 chars so a runaway server response doesn't make a
|
||||
* single failure entry dominate the log file.
|
||||
* single failure entry dominate the result.
|
||||
*/
|
||||
const formatFailureReason = (e: unknown): string => {
|
||||
let message: string;
|
||||
|
||||
@@ -13,8 +13,8 @@ export interface WebDAVConnectFormValues {
|
||||
*
|
||||
* The form's Connect handler only owns the four credential/path fields the
|
||||
* user just typed. Everything else — `deviceId`, `syncBooks`, `strategy`,
|
||||
* `syncProgress`, `syncNotes`, `lastSyncedAt`, `syncLog` — was earned by
|
||||
* prior use and MUST be preserved across a disconnect/reconnect cycle.
|
||||
* `syncProgress`, `syncNotes`, `lastSyncedAt` — was earned by prior use
|
||||
* and MUST be preserved across a disconnect/reconnect cycle.
|
||||
*
|
||||
* Spreading `previous` first lets the form fields shadow the captured
|
||||
* credentials while every bookkeeping field rides through untouched. The
|
||||
@@ -24,7 +24,7 @@ export interface WebDAVConnectFormValues {
|
||||
* Pulled out as a pure helper specifically to unit-test the "reconnect
|
||||
* preserves prior state" invariant: the inline version in WebDAVForm
|
||||
* regressed in PR #4204 by replacing the whole webdav block, which
|
||||
* silently rotated the deviceId and dropped the diagnostic syncLog.
|
||||
* silently rotated the deviceId.
|
||||
*/
|
||||
export const buildWebDAVConnectSettings = (
|
||||
previous: Partial<WebDAVSettings> | undefined,
|
||||
|
||||
@@ -22,8 +22,9 @@ import { create } from 'zustand';
|
||||
* still going).
|
||||
* - We don't track structured progress (counters, per-book status
|
||||
* etc.) — `syncLibrary.onProgress` already builds a localised
|
||||
* label and the UI only ever displays it as a string. Keeping the
|
||||
* store flat avoids re-implementing the formatting in two places.
|
||||
* label, and we keep only a second `progressDetail` string (the
|
||||
* current book's title) so the form can render the status and the
|
||||
* book on separate lines. Formatting still lives in the callback.
|
||||
*
|
||||
* Re-entrancy: callers MUST gate on `isSyncing` *before* flipping it.
|
||||
* The `beginSync` action does not itself enforce mutual exclusion —
|
||||
@@ -35,26 +36,39 @@ interface WebDAVSyncState {
|
||||
/** True while a library-wide Sync now is currently running. */
|
||||
isSyncing: boolean;
|
||||
/**
|
||||
* Localised progress string. Set by `syncLibrary.onProgress` via
|
||||
* `updateProgress`; rendered verbatim by the form. Null when no run
|
||||
* is active.
|
||||
* Localised progress string (the status line, e.g. "Uploading 3 / 12").
|
||||
* Set by `syncLibrary.onProgress` via `updateProgress`. Null when no
|
||||
* run is active.
|
||||
*/
|
||||
progressLabel: string | null;
|
||||
/**
|
||||
* Secondary line under the status — the current book's title. Null
|
||||
* before the first per-book callback (e.g. right after `beginSync`)
|
||||
* and when no run is active.
|
||||
*/
|
||||
progressDetail: string | null;
|
||||
/** Wall-clock millis when the current run kicked off, or null. */
|
||||
startedAt: number | null;
|
||||
|
||||
beginSync: (initialLabel: string) => void;
|
||||
updateProgress: (label: string) => void;
|
||||
updateProgress: (label: string, detail?: string | null) => void;
|
||||
endSync: () => void;
|
||||
}
|
||||
|
||||
export const useWebDAVSyncStore = create<WebDAVSyncState>((set) => ({
|
||||
isSyncing: false,
|
||||
progressLabel: null,
|
||||
progressDetail: null,
|
||||
startedAt: null,
|
||||
|
||||
beginSync: (initialLabel) =>
|
||||
set({ isSyncing: true, progressLabel: initialLabel, startedAt: Date.now() }),
|
||||
updateProgress: (label) => set({ progressLabel: label }),
|
||||
endSync: () => set({ isSyncing: false, progressLabel: null, startedAt: null }),
|
||||
set({
|
||||
isSyncing: true,
|
||||
progressLabel: initialLabel,
|
||||
progressDetail: null,
|
||||
startedAt: Date.now(),
|
||||
}),
|
||||
updateProgress: (label, detail = null) => set({ progressLabel: label, progressDetail: detail }),
|
||||
endSync: () =>
|
||||
set({ isSyncing: false, progressLabel: null, progressDetail: null, startedAt: null }),
|
||||
}));
|
||||
|
||||
@@ -125,100 +125,8 @@ export interface WebDAVSettings {
|
||||
// Wall-clock millisecond timestamp of the last successful end-to-end
|
||||
// sync, surfaced in the WebDAV settings sub-page.
|
||||
lastSyncedAt?: number;
|
||||
// Diagnostic ring buffer: most recent ten "Sync now" runs, oldest first
|
||||
// dropped when full. Persisted alongside the rest of settings so users
|
||||
// can screenshot a failure breakdown when reporting issues. We keep the
|
||||
// cap small both for storage hygiene and because debugging beyond ten
|
||||
// back is rarely useful — by then the live state has long moved on.
|
||||
syncLog?: WebDAVSyncLogEntry[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Outcome category for one entry in {@link WebDAVSettings.syncLog}. We
|
||||
* keep this coarse on purpose — it drives the colour of the status pill
|
||||
* in the history panel and nothing else. Per-step counters travel in the
|
||||
* same entry for users who want detail.
|
||||
*
|
||||
* - `success`: ran to completion with `failures === 0` and at least one
|
||||
* meaningful action (download/upload). "Up to date" runs (no work) also
|
||||
* land here.
|
||||
* - `partial`: ran to completion but `failures > 0`. At least one book
|
||||
* may need a re-sync to fully converge.
|
||||
* - `failure`: did not finish. Either a top-level error (auth failed,
|
||||
* network down before any work) or every book failed.
|
||||
*/
|
||||
export type WebDAVSyncLogStatus = 'success' | 'partial' | 'failure';
|
||||
|
||||
export interface WebDAVSyncLogFailure {
|
||||
/** Stable identifier for the book — used as React key, never displayed. */
|
||||
hash: string;
|
||||
/** Human-readable book title at the time of the failed attempt. */
|
||||
title: string;
|
||||
/**
|
||||
* Short, single-line failure description. We deliberately strip stacks
|
||||
* and long server XML; users want "auth failed" / "404", not a wall of
|
||||
* text. Truncate to ~200 chars at write time so the persisted log
|
||||
* doesn't bloat settings.json.
|
||||
*/
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export interface WebDAVSyncLogEntry {
|
||||
/** UUIDv4. Used as React list key and for "expand details" toggling. */
|
||||
id: string;
|
||||
/** Wall-clock ms when handleSyncNow began. */
|
||||
startedAt: number;
|
||||
/** Wall-clock ms when the run finished or aborted. */
|
||||
finishedAt: number;
|
||||
status: WebDAVSyncLogStatus;
|
||||
/**
|
||||
* What kind of run this entry records. Defaults to 'sync' when
|
||||
* absent so log entries persisted before this field was introduced
|
||||
* keep rendering the same way they always did. 'cleanup' is set
|
||||
* for entries written by the WebDAV browser's batch
|
||||
* Delete-from-server action; renderers use this to swap the badge
|
||||
* label and pick a cleanup-specific summary line.
|
||||
*/
|
||||
kind?: 'sync' | 'cleanup';
|
||||
/**
|
||||
* What kicked off this run. v1 only writes 'manual' (the Sync now
|
||||
* button is the only entry point). The reader-hook auto-pushes are
|
||||
* intentionally NOT logged: they fire once per page-turn and would
|
||||
* drown out the manual-run signal users care about.
|
||||
*/
|
||||
trigger: 'manual' | 'auto';
|
||||
/** Counters mirroring `SyncLibraryResult` — directly screenshot-friendly. */
|
||||
totalBooks: number;
|
||||
booksDownloaded: number;
|
||||
filesUploaded: number;
|
||||
filesAlreadyInSync: number;
|
||||
configsUploaded: number;
|
||||
configsDownloaded: number;
|
||||
coversUploaded: number;
|
||||
/**
|
||||
* Number of per-hash directories successfully removed from the
|
||||
* server in a cleanup run. Only meaningful when `kind === 'cleanup'`;
|
||||
* sync entries leave this undefined / zero. Kept optional to avoid
|
||||
* a migration step on existing settings.json files.
|
||||
*/
|
||||
booksDeleted?: number;
|
||||
failures: number;
|
||||
/** The same one-liner shown in the toast. Kept for at-a-glance reading. */
|
||||
summary: string;
|
||||
/**
|
||||
* Top-level error message when the run aborted before processing
|
||||
* books (auth, root not reachable, connectivity). Mutually exclusive
|
||||
* with `failedBooks` in practice — a top-level abort means we never
|
||||
* iterated, so per-book failures don't apply.
|
||||
*/
|
||||
errorMessage?: string;
|
||||
/** Per-book failure breakdown when `failures > 0`. */
|
||||
failedBooks?: WebDAVSyncLogFailure[];
|
||||
}
|
||||
|
||||
/** Maximum entries retained in {@link WebDAVSettings.syncLog}. */
|
||||
export const WEBDAV_SYNC_LOG_LIMIT = 10;
|
||||
|
||||
/**
|
||||
* User-facing sync categories. 'progress' gates the existing book-config
|
||||
* (reading progress) sync, 'note' gates annotations, 'book' gates book
|
||||
|
||||
Reference in New Issue
Block a user