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:
Huang Xin
2026-06-25 12:10:20 +08:00
committed by GitHub
parent 0c7ffa9799
commit e80ab1762b
45 changed files with 232 additions and 780 deletions
@@ -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": "Sapplique à la bibliothèque",
"Applies to the Reader": "Sapplique à 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,
+23 -9
View File
@@ -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 }),
}));
-92
View File
@@ -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