LwtId الخاص بها.",
"anki.sync.step_open": "انقر الزر أدناه. في المرة الأولى، يسألك Anki هل يثق بهذه الصفحة: وافق.",
- "anki.sync.button": "سحب المراجعات من Anki",
+ "anki.sync.button": "مزامنة المراجعات مع Anki",
"anki.sync.connecting": "جارٍ الاتصال بـ Anki...",
"anki.sync.reading_notes": "قراءة الملاحظات: {done} من {total}",
"anki.sync.reading_reviews": "قراءة المراجعات: البطاقة {done} من {total}",
"anki.sync.sending": "الإرسال إلى LWT: المراجعة {done} من {total}",
- "anki.sync.done": "سُحبت المراجعات من Anki.",
+ "anki.sync.done": "تمت مزامنة المراجعات مع Anki.",
"anki.sync.applied_zero": "لم تُدمج أي مراجعة جديدة",
"anki.sync.applied_one": "دُمجت مراجعة جديدة واحدة",
"anki.sync.applied_two": "دُمجت مراجعتان جديدتان",
@@ -564,9 +564,23 @@
"anki.sync.skipped_other": "تم تجاوز {count} مراجعة (مصطلحات متجاهَلة أو معروفة جيدًا أو محذوفة)",
"anki.sync.error_unreachable": "تعذّر الوصول إلى Anki على {url}. هل Anki مفتوح، وإضافة AnkiConnect مثبّتة؟",
"anki.sync.error_denied": "رفض Anki الوصول. انقر الزر مرة أخرى ووافق على الطلب في Anki.",
- "anki.sync.error_failed": "فشل السحب: {message}",
- "anki.sync.how_html": "تنتقل المراجعات وحدها، من Anki إلى LWT: لا يتغير شيء في Anki. تنضم كل مراجعة إلى سجل المصطلح في اللحظة التي حدثت فيها، لذا فإن الدراسة في التطبيقين بين سحبين تعطي الجدول نفسه الذي كنت ستحصل عليه في تطبيق واحد. السحب مرة أخرى آمن: تُتجاوز المراجعات الموجودة مسبقًا في LWT.",
+ "anki.sync.error_failed": "فشلت المزامنة: {message}",
+ "anki.sync.how_html": "تنتقل المراجعات في الاتجاهين. تنضم كل مراجعة إلى سجل المصطلح في اللحظة التي حدثت فيها، لذا فإن الدراسة في التطبيقين بين مزامنتين تعطي الجدول نفسه الذي كنت ستحصل عليه في تطبيق واحد، ثم تأخذ بطاقات Anki مواعيد الاستحقاق من LWT. المزامنة مرة أخرى آمنة: تُتجاوز المراجعات الموجودة مسبقًا لدى أي من الطرفين. تُزامَن المراجعات والجداول فقط، لا الترجمات ولا الوسوم.",
"anki.sync.hosted_html": "إذا كان LWT يعمل على خادم آخر، فقد يطلب متصفحك إذنًا للوصول إلى Anki على هذا الحاسوب، أو يحظره؛ والسماح بـالوصول إلى الشبكة المحلية لهذا الموقع يحل ذلك. أما تبادل ملفات .apkg فيعمل في كل مكان.",
+ "anki.sync.writing": "الكتابة إلى Anki: {done} من {total}",
+ "anki.sync.pushed_zero": "لم تُرسل أي مراجعة من LWT إلى Anki",
+ "anki.sync.pushed_one": "أُرسلت مراجعة واحدة من LWT إلى Anki",
+ "anki.sync.pushed_two": "أُرسلت مراجعتان من LWT إلى Anki",
+ "anki.sync.pushed_few": "أُرسلت {count} مراجعات من LWT إلى Anki",
+ "anki.sync.pushed_many": "أُرسلت {count} مراجعةً من LWT إلى Anki",
+ "anki.sync.pushed_other": "أُرسلت {count} مراجعة من LWT إلى Anki",
+ "anki.sync.cards_zero": "لم تأخذ أي بطاقة في Anki جدول LWT",
+ "anki.sync.cards_one": "أخذت بطاقة واحدة في Anki جدول LWT",
+ "anki.sync.cards_two": "أخذت بطاقتان في Anki جدول LWT",
+ "anki.sync.cards_few": "أخذت {count} بطاقات في Anki جدول LWT",
+ "anki.sync.cards_many": "أخذت {count} بطاقةً في Anki جدول LWT",
+ "anki.sync.cards_other": "أخذت {count} بطاقة في Anki جدول LWT",
+ "anki.sync.fsrs_html": "عند تفعيل FSRS في Anki، يحتفظ Anki أيضًا بتقديره الخاص للذاكرة لكل بطاقة، ولا تحدّثه المراجعات المرسلة من LWT: إذ لا يستطيع AnkiConnect كتابته. مواعيد الاستحقاق صحيحة؛ ولمواءمة التقديرات أيضًا، شغّل تحسين في خيارات المجموعة في Anki من حين لآخر.",
"titles.terms": "المصطلحات",
"titles.term": "مصطلح",
"titles.term_named": "المصطلح: {term}",
@@ -577,5 +591,5 @@
"titles.error": "خطأ",
"titles.status_changed": "تم تغيير الحالة",
"titles.status_set": "تم تعيين الحالة",
- "titles.anki_sync": "مزامنة المراجعات من Anki"
+ "titles.anki_sync": "مزامنة المراجعات مع Anki"
}
diff --git a/locale/de/vocabulary.json b/locale/de/vocabulary.json
index 252baf972..5818f9bbf 100644
--- a/locale/de/vocabulary.json
+++ b/locale/de/vocabulary.json
@@ -432,17 +432,17 @@
"anki.apkg.settings_import": "Umgekehrt aktivieren Sie Lernfortschritt importieren, wenn Sie ein LWT-Deck in Anki importieren, sonst beginnt Anki jede Karte von vorn und verwirft den von dieser Seite exportierten Lernplan.",
"anki.apkg.deck_notice_title": "Möchten Sie ein in Anki erstelltes Deck importieren?",
"anki.apkg.deck_notice": "Diese Seite aktualisiert nur Begriffe, die ursprünglich von LWT exportiert wurden – ein Deck aus Anki oder AnkiWeb hat hier nichts, womit es abgeglichen werden könnte, es würde sich also nichts ändern. Verwenden Sie stattdessen Ein Anki-Deck importieren: Dort werden neue Begriffe erstellt und anhand von Ankis eigenem Lernplan ermittelt, wie gut Sie jedes Wort kennen.",
- "anki.sync.link": "Wiederholungen aus Anki abrufen (AnkiConnect)",
- "anki.sync.intro": "Übernehmen Sie Ihre Wiederholungen aus Anki direkt von diesem Computer in den Lernplan von LWT – ohne Datei zum Exportieren oder Importieren.",
+ "anki.sync.link": "Wiederholungen mit Anki synchronisieren (AnkiConnect)",
+ "anki.sync.intro": "Übernehmen Sie Ihre Wiederholungen aus Anki in LWT und senden Sie die in LWT erledigten an Anki – direkt mit Anki auf diesem Computer, ohne Datei zum Exportieren oder Importieren.",
"anki.sync.step_addon_html": "Installieren Sie das Add-on AnkiConnect und lassen Sie Anki geöffnet.",
"anki.sync.step_export_html": "Ihre Karten müssen aus LWT stammen: Exportieren Sie sie einmal mit Sprache als Anki-Paket (.apkg) exportieren, damit jede Notiz ihre LwtId enthält.",
"anki.sync.step_open": "Klicken Sie auf die Schaltfläche unten. Beim ersten Mal fragt Anki, ob es dieser Seite vertrauen soll: Bestätigen Sie.",
- "anki.sync.button": "Wiederholungen aus Anki abrufen",
+ "anki.sync.button": "Wiederholungen mit Anki synchronisieren",
"anki.sync.connecting": "Verbindung zu Anki wird hergestellt...",
"anki.sync.reading_notes": "Notizen werden gelesen: {done} von {total}",
"anki.sync.reading_reviews": "Wiederholungen werden gelesen: {done} von {total} Karten",
"anki.sync.sending": "Senden an LWT: {done} von {total} Wiederholungen",
- "anki.sync.done": "Wiederholungen aus Anki abgerufen.",
+ "anki.sync.done": "Wiederholungen mit Anki synchronisiert.",
"anki.sync.applied_one": "{count} neue Wiederholung übernommen",
"anki.sync.applied_other": "{count} neue Wiederholungen übernommen",
"anki.sync.terms_one": "{count} Begriff neu geplant",
@@ -455,9 +455,15 @@
"anki.sync.skipped_other": "{count} Wiederholungen übersprungen (ignorierte, bekannte oder gelöschte Begriffe)",
"anki.sync.error_unreachable": "Anki unter {url} nicht erreichbar. Ist Anki geöffnet und das Add-on AnkiConnect installiert?",
"anki.sync.error_denied": "Anki hat den Zugriff verweigert. Klicken Sie erneut auf die Schaltfläche und bestätigen Sie die Abfrage in Anki.",
- "anki.sync.error_failed": "Abruf fehlgeschlagen: {message}",
- "anki.sync.how_html": "Nur Wiederholungen werden übertragen, von Anki nach LWT: In Anki wird nichts geändert. Jede Wiederholung wird zum Zeitpunkt, an dem sie stattfand, in den Verlauf des Begriffs eingefügt. Wer zwischen zwei Abrufen in beiden Apps lernt, erhält also denselben Lernplan wie in einer einzigen. Erneutes Abrufen ist unbedenklich: Wiederholungen, die LWT bereits hat, werden übersprungen.",
+ "anki.sync.error_failed": "Synchronisierung fehlgeschlagen: {message}",
+ "anki.sync.how_html": "Wiederholungen werden in beide Richtungen übertragen. Jede wird zum Zeitpunkt, an dem sie stattfand, in den Verlauf des Begriffs eingefügt. Wer zwischen zwei Synchronisierungen in beiden Apps lernt, erhält also denselben Lernplan wie in einer einzigen, und die Karten in Anki übernehmen danach die Fälligkeitsdaten von LWT. Erneutes Synchronisieren ist unbedenklich: Wiederholungen, die eine Seite bereits hat, werden übersprungen. Synchronisiert werden nur Wiederholungen und Lernpläne, keine Übersetzungen oder Schlagwörter.",
"anki.sync.hosted_html": "Läuft LWT auf einem anderen Server, fragt Ihr Browser möglicherweise nach der Berechtigung, Anki auf diesem Computer zu erreichen, oder blockiert dies; wenn Sie für diese Website den Zugriff auf das lokale Netzwerk erlauben, ist das behoben. Der Weg über eine .apkg-Datei funktioniert überall.",
+ "anki.sync.writing": "Schreiben in Anki: {done} von {total}",
+ "anki.sync.pushed_one": "{count} LWT-Wiederholung an Anki gesendet",
+ "anki.sync.pushed_other": "{count} LWT-Wiederholungen an Anki gesendet",
+ "anki.sync.cards_one": "{count} Anki-Karte hat den Lernplan von LWT erhalten",
+ "anki.sync.cards_other": "{count} Anki-Karten haben den Lernplan von LWT erhalten",
+ "anki.sync.fsrs_html": "Ist FSRS in Anki aktiviert, führt Anki für jede Karte zusätzlich eine eigene Gedächtnisschätzung, die von LWT gesendete Wiederholungen nicht aktualisieren: AnkiConnect kann sie nicht schreiben. Die Fälligkeitsdaten stimmen; um auch die Schätzungen anzugleichen, führen Sie ab und zu Optimieren in den Stapeloptionen von Anki aus.",
"titles.terms": "Begriffe",
"titles.term": "Begriff",
"titles.term_named": "Begriff: {term}",
@@ -468,5 +474,5 @@
"titles.error": "Fehler",
"titles.status_changed": "Status geändert",
"titles.status_set": "Status gesetzt",
- "titles.anki_sync": "Wiederholungen aus Anki synchronisieren"
+ "titles.anki_sync": "Wiederholungen mit Anki synchronisieren"
}
diff --git a/locale/en/vocabulary.json b/locale/en/vocabulary.json
index 0ed51c261..1c878e208 100644
--- a/locale/en/vocabulary.json
+++ b/locale/en/vocabulary.json
@@ -419,17 +419,17 @@
"anki.apkg.settings_import": "Going the other way, tick Import any learning progress when you import an LWT deck into Anki, or Anki starts every card from scratch and discards the schedule this page exported.",
"anki.apkg.deck_notice_title": "Importing a deck you built in Anki?",
"anki.apkg.deck_notice": "This page only updates terms that LWT exported in the first place — a deck from Anki or AnkiWeb has nothing here to match against, so nothing would change. Use Import an Anki deck instead, which creates new terms and works out how well you know each word from Anki's own scheduling.",
- "anki.sync.link": "Pull reviews from Anki (AnkiConnect)",
- "anki.sync.intro": "Bring the reviews you did in Anki into LWT's schedule, straight from Anki on this computer: no file to export or import.",
+ "anki.sync.link": "Sync reviews with Anki (AnkiConnect)",
+ "anki.sync.intro": "Bring the reviews you did in Anki into LWT, and send the ones you did in LWT to Anki, straight from Anki on this computer: no file to export or import.",
"anki.sync.step_addon_html": "Install the AnkiConnect add-on, and keep Anki open.",
"anki.sync.step_export_html": "Your cards must come from LWT: export them once with Export Language to Anki package (.apkg), so that each note carries its LwtId.",
"anki.sync.step_open": "Click the button below. The first time, Anki asks whether to trust this page: accept.",
- "anki.sync.button": "Pull reviews from Anki",
+ "anki.sync.button": "Sync reviews with Anki",
"anki.sync.connecting": "Connecting to Anki...",
"anki.sync.reading_notes": "Reading notes: {done} of {total}",
"anki.sync.reading_reviews": "Reading reviews: {done} of {total} cards",
"anki.sync.sending": "Sending to LWT: {done} of {total} reviews",
- "anki.sync.done": "Reviews pulled from Anki.",
+ "anki.sync.done": "Reviews synced with Anki.",
"anki.sync.applied_one": "{count} new review merged",
"anki.sync.applied_other": "{count} new reviews merged",
"anki.sync.terms_one": "{count} term rescheduled",
@@ -442,9 +442,15 @@
"anki.sync.skipped_other": "{count} reviews skipped (ignored, well-known or deleted terms)",
"anki.sync.error_unreachable": "Could not reach Anki at {url}. Is Anki open, with the AnkiConnect add-on installed?",
"anki.sync.error_denied": "Anki refused access. Click the button again and accept the prompt in Anki.",
- "anki.sync.error_failed": "The pull failed: {message}",
- "anki.sync.how_html": "Only reviews travel, from Anki to LWT: nothing in Anki is changed. Each review joins the term's history at the moment it happened, so studying in both apps between two pulls gives the schedule you would have had in one. Pulling again is safe: reviews LWT already has are skipped.",
+ "anki.sync.error_failed": "The sync failed: {message}",
+ "anki.sync.how_html": "Reviews travel both ways. Each joins the term's history at the moment it happened, so studying in both apps between two syncs gives the schedule you would have had in one, and Anki's cards then get LWT's due dates. Syncing again is safe: reviews either side already has are skipped. Only reviews and schedules are synced, not translations or tags.",
"anki.sync.hosted_html": "If LWT runs on another server, your browser may ask for permission to reach Anki on this computer, or block it; allowing local network access for this site fixes that. The .apkg file round trip works everywhere.",
+ "anki.sync.writing": "Writing to Anki: {done} of {total}",
+ "anki.sync.pushed_one": "{count} LWT review sent to Anki",
+ "anki.sync.pushed_other": "{count} LWT reviews sent to Anki",
+ "anki.sync.cards_one": "{count} Anki card given LWT's schedule",
+ "anki.sync.cards_other": "{count} Anki cards given LWT's schedule",
+ "anki.sync.fsrs_html": "With FSRS on in Anki, Anki also keeps its own memory estimate for each card, which reviews sent from LWT do not update: AnkiConnect cannot write it. The due dates are right; to bring the estimates in line too, run Optimize in Anki's deck options now and then.",
"titles.terms": "Terms",
"titles.term": "Term",
"titles.term_named": "Term: {term}",
@@ -455,5 +461,5 @@
"titles.error": "Error",
"titles.status_changed": "Status Changed",
"titles.status_set": "Status Set",
- "titles.anki_sync": "Sync Reviews from Anki"
+ "titles.anki_sync": "Sync Reviews with Anki"
}
diff --git a/locale/es/vocabulary.json b/locale/es/vocabulary.json
index 3d12be594..aed95abe0 100644
--- a/locale/es/vocabulary.json
+++ b/locale/es/vocabulary.json
@@ -436,17 +436,17 @@
"anki.apkg.settings_import": "En sentido inverso, marca Importar el progreso de aprendizaje cuando importes un mazo de LWT en Anki, o Anki empezará cada tarjeta desde cero y descartará la programación que exportó esta página.",
"anki.apkg.deck_notice_title": "¿Vas a importar un mazo que creaste en Anki?",
"anki.apkg.deck_notice": "Esta página solo actualiza términos que LWT exportó en primer lugar: un mazo de Anki o de AnkiWeb no tiene nada aquí con lo que emparejarse, así que no cambiaría nada. Usa en su lugar Importar un mazo de Anki, que crea términos nuevos y deduce lo bien que conoces cada palabra a partir de la propia programación de Anki.",
- "anki.sync.link": "Traer repasos desde Anki (AnkiConnect)",
- "anki.sync.intro": "Lleva los repasos que hiciste en Anki a la programación de LWT, directamente desde Anki en este ordenador: sin archivos que exportar ni importar.",
+ "anki.sync.link": "Sincronizar repasos con Anki (AnkiConnect)",
+ "anki.sync.intro": "Lleva a LWT los repasos que hiciste en Anki y envía a Anki los que hiciste en LWT, directamente desde Anki en este ordenador: sin archivos que exportar ni importar.",
"anki.sync.step_addon_html": "Instala el complemento AnkiConnect y deja Anki abierto.",
"anki.sync.step_export_html": "Tus tarjetas deben venir de LWT: expórtalas una vez con Exportar idioma a paquete Anki (.apkg), para que cada nota lleve su LwtId.",
"anki.sync.step_open": "Haz clic en el botón de abajo. La primera vez, Anki pregunta si confiar en esta página: acepta.",
- "anki.sync.button": "Traer repasos desde Anki",
+ "anki.sync.button": "Sincronizar repasos con Anki",
"anki.sync.connecting": "Conectando con Anki...",
"anki.sync.reading_notes": "Leyendo notas: {done} de {total}",
"anki.sync.reading_reviews": "Leyendo repasos: {done} de {total} tarjetas",
"anki.sync.sending": "Enviando a LWT: {done} de {total} repasos",
- "anki.sync.done": "Repasos traídos desde Anki.",
+ "anki.sync.done": "Repasos sincronizados con Anki.",
"anki.sync.applied_one": "{count} repaso nuevo incorporado",
"anki.sync.applied_other": "{count} repasos nuevos incorporados",
"anki.sync.terms_one": "{count} término reprogramado",
@@ -459,9 +459,15 @@
"anki.sync.skipped_other": "{count} repasos omitidos (términos ignorados, bien conocidos o eliminados)",
"anki.sync.error_unreachable": "No se pudo conectar con Anki en {url}. ¿Está Anki abierto y el complemento AnkiConnect instalado?",
"anki.sync.error_denied": "Anki denegó el acceso. Vuelve a hacer clic en el botón y acepta el aviso en Anki.",
- "anki.sync.error_failed": "No se pudieron traer los repasos: {message}",
- "anki.sync.how_html": "Solo viajan los repasos, de Anki a LWT: no se cambia nada en Anki. Cada repaso se incorpora al historial del término en el momento en que ocurrió, así que estudiar en ambas aplicaciones entre dos sincronizaciones da la misma programación que habrías tenido en una sola. Volver a traerlos es seguro: se omiten los repasos que LWT ya tiene.",
+ "anki.sync.error_failed": "La sincronización falló: {message}",
+ "anki.sync.how_html": "Los repasos viajan en ambos sentidos. Cada uno se incorpora al historial del término en el momento en que ocurrió, así que estudiar en ambas aplicaciones entre dos sincronizaciones da la misma programación que habrías tenido en una sola, y luego las tarjetas de Anki reciben las fechas de vencimiento de LWT. Volver a sincronizar es seguro: se omiten los repasos que cualquiera de los dos lados ya tiene. Solo se sincronizan los repasos y la programación, no las traducciones ni las etiquetas.",
"anki.sync.hosted_html": "Si LWT se ejecuta en otro servidor, tu navegador puede pedir permiso para acceder a Anki en este ordenador, o bloquearlo; permitir el acceso a la red local para este sitio lo soluciona. El intercambio con un archivo .apkg funciona en todas partes.",
+ "anki.sync.writing": "Escribiendo en Anki: {done} de {total}",
+ "anki.sync.pushed_one": "{count} repaso de LWT enviado a Anki",
+ "anki.sync.pushed_other": "{count} repasos de LWT enviados a Anki",
+ "anki.sync.cards_one": "{count} tarjeta de Anki recibió la programación de LWT",
+ "anki.sync.cards_other": "{count} tarjetas de Anki recibieron la programación de LWT",
+ "anki.sync.fsrs_html": "Con FSRS activado en Anki, Anki también guarda su propia estimación de memoria para cada tarjeta, que los repasos enviados desde LWT no actualizan: AnkiConnect no puede escribirla. Las fechas de vencimiento son correctas; para ajustar también las estimaciones, ejecuta de vez en cuando Optimizar en las opciones del mazo de Anki.",
"titles.terms": "Términos",
"titles.term": "Término",
"titles.term_named": "Término: {term}",
@@ -472,5 +478,5 @@
"titles.error": "Error",
"titles.status_changed": "Estado cambiado",
"titles.status_set": "Estado establecido",
- "titles.anki_sync": "Sincronizar repasos desde Anki"
+ "titles.anki_sync": "Sincronizar repasos con Anki"
}
diff --git a/locale/fa/vocabulary.json b/locale/fa/vocabulary.json
index 730bf3370..5958c8246 100644
--- a/locale/fa/vocabulary.json
+++ b/locale/fa/vocabulary.json
@@ -407,17 +407,17 @@
"anki.apkg.settings_import": "در جهت عکس، هنگام درونریزی یک دستهٔ LWT در Anki، گزینهٔ Import any learning progress را علامت بزنید، وگرنه Anki همهٔ کارتها را از صفر شروع میکند و زمانبندیای را که این صفحه برونبری کرده دور میریزد.",
"anki.apkg.deck_notice_title": "دستهای را درونریزی میکنید که در Anki ساختهاید؟",
"anki.apkg.deck_notice": "این صفحه فقط واژههایی را بهروزرسانی میکند که در اصل از LWT برونبری شدهاند — دستهای از Anki یا AnkiWeb در اینجا چیزی برای تطبیق ندارد، پس چیزی تغییر نمیکند. بهجای آن از درونریزی یک دستهٔ Anki استفاده کنید که واژههای جدید میسازد و میزان آشنایی شما با هر واژه را از زمانبندی خودِ Anki استخراج میکند.",
- "anki.sync.link": "دریافت مرورها از Anki (AnkiConnect)",
- "anki.sync.intro": "مرورهایی را که در Anki انجام دادهاید، مستقیماً از Anki روی همین رایانه به زمانبندی LWT بیاورید: بدون برونبری یا درونریزی فایل.",
+ "anki.sync.link": "همگامسازی مرورها با Anki (AnkiConnect)",
+ "anki.sync.intro": "مرورهایی را که در Anki انجام دادهاید به LWT بیاورید و مرورهای LWT را به Anki بفرستید، مستقیماً از Anki روی همین رایانه: بدون برونبری یا درونریزی فایل.",
"anki.sync.step_addon_html": "افزونهٔ AnkiConnect را نصب کنید و Anki را باز نگه دارید.",
"anki.sync.step_export_html": "کارتهای شما باید از LWT آمده باشند: یک بار آنها را با برونبری زبان به بستهٔ Anki (.apkg) برونبری کنید تا هر یادداشت LwtId خود را داشته باشد.",
"anki.sync.step_open": "روی دکمهٔ زیر کلیک کنید. بار اول، Anki میپرسد که آیا به این صفحه اعتماد کند: بپذیرید.",
- "anki.sync.button": "دریافت مرورها از Anki",
+ "anki.sync.button": "همگامسازی مرورها با Anki",
"anki.sync.connecting": "در حال اتصال به Anki...",
"anki.sync.reading_notes": "خواندن یادداشتها: {done} از {total}",
"anki.sync.reading_reviews": "خواندن مرورها: {done} از {total} کارت",
"anki.sync.sending": "ارسال به LWT: {done} از {total} مرور",
- "anki.sync.done": "مرورها از Anki دریافت شدند.",
+ "anki.sync.done": "مرورها با Anki همگام شدند.",
"anki.sync.applied_other": "{count} مرور جدید ادغام شد",
"anki.sync.terms_other": "زمانبندی {count} واژه بهروزرسانی شد",
"anki.sync.duplicates_other": "{count} مرور از قبل در LWT بود",
@@ -425,9 +425,13 @@
"anki.sync.skipped_other": "{count} مرور رد شد (واژهٔ نادیدهگرفته، کاملاً شناختهشده یا حذفشده)",
"anki.sync.error_unreachable": "دسترسی به Anki در {url} ممکن نشد. آیا Anki باز است و افزونهٔ AnkiConnect نصب شده است؟",
"anki.sync.error_denied": "Anki دسترسی را رد کرد. دوباره روی دکمه کلیک کنید و درخواست را در Anki بپذیرید.",
- "anki.sync.error_failed": "دریافت ناموفق بود: {message}",
- "anki.sync.how_html": "فقط مرورها جابهجا میشوند، از Anki به LWT: هیچ چیز در Anki تغییر نمیکند. هر مرور در همان لحظهای که انجام شده به تاریخچهٔ واژه میپیوندد، پس مطالعه در هر دو برنامه بین دو دریافت، همان زمانبندیای را میدهد که با یک برنامه میداشتید. دریافت دوباره بیخطر است: مرورهایی که LWT از قبل دارد رد میشوند.",
+ "anki.sync.error_failed": "همگامسازی ناموفق بود: {message}",
+ "anki.sync.how_html": "مرورها در هر دو جهت جابهجا میشوند. هر مرور در همان لحظهای که انجام شده به تاریخچهٔ واژه میپیوندد، پس مطالعه در هر دو برنامه بین دو همگامسازی، همان زمانبندیای را میدهد که با یک برنامه میداشتید، و سپس کارتهای Anki موعدهای LWT را میگیرند. همگامسازی دوباره بیخطر است: مرورهایی که هر طرف از قبل دارد رد میشوند. فقط مرورها و زمانبندیها همگام میشوند، نه ترجمهها یا برچسبها.",
"anki.sync.hosted_html": "اگر LWT روی سرور دیگری اجرا میشود، مرورگر شما ممکن است برای دسترسی به Anki روی این رایانه اجازه بخواهد یا آن را مسدود کند؛ اجازه دادن دسترسی به شبکهٔ محلی برای این سایت مشکل را حل میکند. رفتوبرگشت با فایل .apkg همهجا کار میکند.",
+ "anki.sync.writing": "نوشتن در Anki: {done} از {total}",
+ "anki.sync.pushed_other": "{count} مرور LWT به Anki فرستاده شد",
+ "anki.sync.cards_other": "زمانبندی LWT به {count} کارت Anki داده شد",
+ "anki.sync.fsrs_html": "اگر FSRS در Anki روشن باشد، Anki برای هر کارت برآورد حافظهٔ خودش را هم نگه میدارد که مرورهای فرستادهشده از LWT آن را بهروز نمیکنند: AnkiConnect نمیتواند آن را بنویسد. موعدها درستاند؛ برای هماهنگ کردن برآوردها نیز، هر از گاهی بهینهسازی را در گزینههای دستهٔ Anki اجرا کنید.",
"titles.terms": "واژهها",
"titles.term": "واژه",
"titles.term_named": "واژه: {term}",
@@ -438,5 +442,5 @@
"titles.error": "خطا",
"titles.status_changed": "وضعیت تغییر کرد",
"titles.status_set": "وضعیت تنظیم شد",
- "titles.anki_sync": "همگامسازی مرورها از Anki"
+ "titles.anki_sync": "همگامسازی مرورها با Anki"
}
diff --git a/locale/fr/vocabulary.json b/locale/fr/vocabulary.json
index 4cb4063c7..608ed5ef8 100644
--- a/locale/fr/vocabulary.json
+++ b/locale/fr/vocabulary.json
@@ -435,17 +435,17 @@
"anki.apkg.settings_import": "Dans l'autre sens, cochez Importer la progression d'apprentissage lorsque vous importez un paquet LWT dans Anki, sinon Anki repart de zéro pour chaque carte et ignore la planification exportée par cette page.",
"anki.apkg.deck_notice_title": "Vous importez un paquet créé dans Anki ?",
"anki.apkg.deck_notice": "Cette page ne met à jour que les termes exportés par LWT au départ — un paquet venant d'Anki ou d'AnkiWeb n'a rien ici à quoi correspondre, rien ne changerait donc. Utilisez plutôt Importer un paquet Anki, qui crée de nouveaux termes et détermine votre niveau de connaissance de chaque mot à partir de la planification d'Anki.",
- "anki.sync.link": "Récupérer les révisions d'Anki (AnkiConnect)",
- "anki.sync.intro": "Intégrez les révisions faites dans Anki à la planification de LWT, directement depuis Anki sur cet ordinateur : aucun fichier à exporter ni à importer.",
+ "anki.sync.link": "Synchroniser les révisions avec Anki (AnkiConnect)",
+ "anki.sync.intro": "Intégrez à LWT les révisions faites dans Anki, et envoyez à Anki celles faites dans LWT, directement depuis Anki sur cet ordinateur : aucun fichier à exporter ni à importer.",
"anki.sync.step_addon_html": "Installez l'extension AnkiConnect et laissez Anki ouvert.",
"anki.sync.step_export_html": "Vos cartes doivent venir de LWT : exportez-les une fois avec Exporter la langue en paquet Anki (.apkg), pour que chaque note porte son LwtId.",
"anki.sync.step_open": "Cliquez sur le bouton ci-dessous. La première fois, Anki demande s'il faut faire confiance à cette page : acceptez.",
- "anki.sync.button": "Récupérer les révisions d'Anki",
+ "anki.sync.button": "Synchroniser les révisions avec Anki",
"anki.sync.connecting": "Connexion à Anki...",
"anki.sync.reading_notes": "Lecture des notes : {done} sur {total}",
"anki.sync.reading_reviews": "Lecture des révisions : {done} cartes sur {total}",
"anki.sync.sending": "Envoi à LWT : {done} révisions sur {total}",
- "anki.sync.done": "Révisions récupérées depuis Anki.",
+ "anki.sync.done": "Révisions synchronisées avec Anki.",
"anki.sync.applied_one": "{count} nouvelle révision intégrée",
"anki.sync.applied_other": "{count} nouvelles révisions intégrées",
"anki.sync.terms_one": "{count} terme replanifié",
@@ -458,9 +458,15 @@
"anki.sync.skipped_other": "{count} révisions sautées (termes ignorés, bien connus ou supprimés)",
"anki.sync.error_unreachable": "Impossible de joindre Anki à l'adresse {url}. Anki est-il ouvert, avec l'extension AnkiConnect installée ?",
"anki.sync.error_denied": "Anki a refusé l'accès. Cliquez à nouveau sur le bouton et acceptez la demande dans Anki.",
- "anki.sync.error_failed": "La récupération a échoué : {message}",
- "anki.sync.how_html": "Seules les révisions voyagent, d'Anki vers LWT : rien n'est modifié dans Anki. Chaque révision rejoint l'historique du terme au moment où elle a eu lieu ; étudier dans les deux applications entre deux récupérations donne donc la planification que vous auriez eue dans une seule. Récupérer à nouveau est sans risque : les révisions que LWT possède déjà sont ignorées.",
+ "anki.sync.error_failed": "La synchronisation a échoué : {message}",
+ "anki.sync.how_html": "Les révisions voyagent dans les deux sens. Chacune rejoint l'historique du terme au moment où elle a eu lieu ; étudier dans les deux applications entre deux synchronisations donne donc la planification que vous auriez eue dans une seule, et les cartes d'Anki reçoivent ensuite les échéances de LWT. Synchroniser à nouveau est sans risque : les révisions que l'un ou l'autre côté possède déjà sont ignorées. Seules les révisions et les planifications sont synchronisées, pas les traductions ni les étiquettes.",
"anki.sync.hosted_html": "Si LWT tourne sur un autre serveur, votre navigateur peut demander l'autorisation de joindre Anki sur cet ordinateur, ou le bloquer ; autoriser l'accès au réseau local pour ce site règle le problème. L'aller-retour par fichier .apkg fonctionne partout.",
+ "anki.sync.writing": "Écriture dans Anki : {done} sur {total}",
+ "anki.sync.pushed_one": "{count} révision LWT envoyée à Anki",
+ "anki.sync.pushed_other": "{count} révisions LWT envoyées à Anki",
+ "anki.sync.cards_one": "{count} carte Anki a reçu la planification de LWT",
+ "anki.sync.cards_other": "{count} cartes Anki ont reçu la planification de LWT",
+ "anki.sync.fsrs_html": "Avec FSRS activé dans Anki, Anki tient aussi sa propre estimation de mémorisation pour chaque carte, que les révisions envoyées depuis LWT ne mettent pas à jour : AnkiConnect ne peut pas l'écrire. Les échéances sont justes ; pour aligner aussi les estimations, lancez de temps en temps Optimiser dans les options du paquet d'Anki.",
"titles.terms": "Termes",
"titles.term": "Terme",
"titles.term_named": "Terme: {term}",
@@ -471,5 +477,5 @@
"titles.error": "Erreur",
"titles.status_changed": "Statut modifié",
"titles.status_set": "Statut défini",
- "titles.anki_sync": "Synchroniser les révisions depuis Anki"
+ "titles.anki_sync": "Synchroniser les révisions avec Anki"
}
diff --git a/locale/it/vocabulary.json b/locale/it/vocabulary.json
index eb02eb2a6..35ebc54d7 100644
--- a/locale/it/vocabulary.json
+++ b/locale/it/vocabulary.json
@@ -436,17 +436,17 @@
"anki.apkg.settings_import": "Nella direzione opposta, spunta Importa i progressi di apprendimento quando importi un mazzo LWT in Anki, altrimenti Anki ricomincia ogni carta da zero e scarta la pianificazione esportata da questa pagina.",
"anki.apkg.deck_notice_title": "Stai importando un mazzo creato in Anki?",
"anki.apkg.deck_notice": "Questa pagina aggiorna solo i termini che LWT ha esportato in origine: un mazzo proveniente da Anki o AnkiWeb non ha nulla qui con cui essere confrontato, quindi non cambierebbe niente. Usa invece Importa un mazzo Anki, che crea nuovi termini e deduce quanto conosci ogni parola dalla pianificazione di Anki.",
- "anki.sync.link": "Recupera le ripetizioni da Anki (AnkiConnect)",
- "anki.sync.intro": "Porta le ripetizioni fatte in Anki nella pianificazione di LWT, direttamente da Anki su questo computer: nessun file da esportare o importare.",
+ "anki.sync.link": "Sincronizza le ripetizioni con Anki (AnkiConnect)",
+ "anki.sync.intro": "Porta in LWT le ripetizioni fatte in Anki e invia ad Anki quelle fatte in LWT, direttamente da Anki su questo computer: nessun file da esportare o importare.",
"anki.sync.step_addon_html": "Installa il componente aggiuntivo AnkiConnect e tieni Anki aperto.",
"anki.sync.step_export_html": "Le tue carte devono provenire da LWT: esportale una volta con Esporta lingua come pacchetto Anki (.apkg), così che ogni nota contenga il suo LwtId.",
"anki.sync.step_open": "Fai clic sul pulsante qui sotto. La prima volta Anki chiede se fidarsi di questa pagina: accetta.",
- "anki.sync.button": "Recupera le ripetizioni da Anki",
+ "anki.sync.button": "Sincronizza le ripetizioni con Anki",
"anki.sync.connecting": "Connessione ad Anki...",
"anki.sync.reading_notes": "Lettura delle note: {done} di {total}",
"anki.sync.reading_reviews": "Lettura delle ripetizioni: {done} di {total} carte",
"anki.sync.sending": "Invio a LWT: {done} di {total} ripetizioni",
- "anki.sync.done": "Ripetizioni recuperate da Anki.",
+ "anki.sync.done": "Ripetizioni sincronizzate con Anki.",
"anki.sync.applied_one": "{count} nuova ripetizione integrata",
"anki.sync.applied_other": "{count} nuove ripetizioni integrate",
"anki.sync.terms_one": "{count} termine ripianificato",
@@ -459,9 +459,15 @@
"anki.sync.skipped_other": "{count} ripetizioni saltate (termini ignorati, ben noti o eliminati)",
"anki.sync.error_unreachable": "Impossibile raggiungere Anki su {url}. Anki è aperto e il componente aggiuntivo AnkiConnect è installato?",
"anki.sync.error_denied": "Anki ha negato l'accesso. Fai di nuovo clic sul pulsante e accetta la richiesta in Anki.",
- "anki.sync.error_failed": "Recupero non riuscito: {message}",
- "anki.sync.how_html": "Viaggiano solo le ripetizioni, da Anki a LWT: in Anki non cambia nulla. Ogni ripetizione entra nella cronologia del termine nel momento in cui è avvenuta, quindi studiare in entrambe le app tra due recuperi dà la stessa pianificazione che avresti avuto in una sola. Recuperare di nuovo è sicuro: le ripetizioni che LWT ha già vengono saltate.",
+ "anki.sync.error_failed": "Sincronizzazione non riuscita: {message}",
+ "anki.sync.how_html": "Le ripetizioni viaggiano in entrambe le direzioni. Ognuna entra nella cronologia del termine nel momento in cui è avvenuta, quindi studiare in entrambe le app tra due sincronizzazioni dà la stessa pianificazione che avresti avuto in una sola, e le carte di Anki ricevono poi le scadenze di LWT. Sincronizzare di nuovo è sicuro: le ripetizioni che una delle due parti ha già vengono saltate. Si sincronizzano solo ripetizioni e pianificazioni, non traduzioni o etichette.",
"anki.sync.hosted_html": "Se LWT è in esecuzione su un altro server, il browser potrebbe chiedere il permesso di raggiungere Anki su questo computer, oppure bloccarlo; consentire l'accesso alla rete locale per questo sito risolve il problema. Il passaggio tramite file .apkg funziona ovunque.",
+ "anki.sync.writing": "Scrittura in Anki: {done} di {total}",
+ "anki.sync.pushed_one": "{count} ripetizione LWT inviata ad Anki",
+ "anki.sync.pushed_other": "{count} ripetizioni LWT inviate ad Anki",
+ "anki.sync.cards_one": "{count} carta Anki ha ricevuto la pianificazione di LWT",
+ "anki.sync.cards_other": "{count} carte Anki hanno ricevuto la pianificazione di LWT",
+ "anki.sync.fsrs_html": "Con FSRS attivo in Anki, Anki tiene anche una propria stima della memoria per ogni carta, che le ripetizioni inviate da LWT non aggiornano: AnkiConnect non può scriverla. Le scadenze sono corrette; per allineare anche le stime, esegui ogni tanto Ottimizza nelle opzioni del mazzo di Anki.",
"titles.terms": "Termini",
"titles.term": "Termine",
"titles.term_named": "Termine: {term}",
@@ -472,5 +478,5 @@
"titles.error": "Errore",
"titles.status_changed": "Stato modificato",
"titles.status_set": "Stato impostato",
- "titles.anki_sync": "Sincronizza le ripetizioni da Anki"
+ "titles.anki_sync": "Sincronizza le ripetizioni con Anki"
}
diff --git a/locale/ja/vocabulary.json b/locale/ja/vocabulary.json
index 5748564cc..53c00120b 100644
--- a/locale/ja/vocabulary.json
+++ b/locale/ja/vocabulary.json
@@ -418,17 +418,17 @@
"anki.apkg.settings_import": "逆方向では、LWT のデッキを Anki にインポートする際に 学習の進捗をインポートする にチェックを入れてください。そうしないと Anki はすべてのカードを最初から始め、このページがエクスポートしたスケジュールを破棄します。",
"anki.apkg.deck_notice_title": "Anki で作成したデッキをインポートしますか?",
"anki.apkg.deck_notice": "このページは、もともと LWT がエクスポートした用語だけを更新します。Anki や AnkiWeb のデッキには照合できるものがここにないため、何も変わりません。代わりに Anki デッキをインポート を使用してください。新しい用語を作成し、Anki 自身のスケジュールから各単語の習熟度を判定します。",
- "anki.sync.link": "Anki から復習を取り込む(AnkiConnect)",
- "anki.sync.intro": "Anki で行った復習を、このコンピューター上の Anki から直接 LWT のスケジュールに取り込みます。ファイルのエクスポートやインポートは不要です。",
+ "anki.sync.link": "Anki と復習を同期する(AnkiConnect)",
+ "anki.sync.intro": "Anki で行った復習を LWT に取り込み、LWT で行った復習を Anki に送ります。このコンピューター上の Anki と直接やり取りするので、ファイルのエクスポートやインポートは不要です。",
"anki.sync.step_addon_html": "AnkiConnect アドオンをインストールし、Anki を開いたままにしてください。",
"anki.sync.step_export_html": "カードは LWT から作成したものである必要があります。各ノートが LwtId を持つよう、一度 言語全体を Anki パッケージ(.apkg)にエクスポート でエクスポートしてください。",
"anki.sync.step_open": "下のボタンをクリックしてください。初回は、このページを信頼するかどうか Anki が尋ねるので、許可してください。",
- "anki.sync.button": "Anki から復習を取り込む",
+ "anki.sync.button": "Anki と復習を同期する",
"anki.sync.connecting": "Anki に接続中...",
"anki.sync.reading_notes": "ノートを読み込み中: {done} / {total}",
"anki.sync.reading_reviews": "復習を読み込み中: {done} / {total} カード",
"anki.sync.sending": "LWT に送信中: {done} / {total} 件の復習",
- "anki.sync.done": "Anki から復習を取り込みました。",
+ "anki.sync.done": "Anki と復習を同期しました。",
"anki.sync.applied_other": "{count} 件の新しい復習を統合しました",
"anki.sync.terms_other": "{count} 件の用語のスケジュールを更新しました",
"anki.sync.duplicates_other": "{count} 件の復習は LWT に既にありました",
@@ -436,9 +436,13 @@
"anki.sync.skipped_other": "{count} 件の復習をスキップしました(無視・よく知っている・削除済みの用語)",
"anki.sync.error_unreachable": "{url} で Anki に接続できませんでした。Anki が開いていて、AnkiConnect アドオンがインストールされているか確認してください。",
"anki.sync.error_denied": "Anki がアクセスを拒否しました。もう一度ボタンをクリックし、Anki の確認画面で許可してください。",
- "anki.sync.error_failed": "取り込みに失敗しました: {message}",
- "anki.sync.how_html": "復習だけが Anki から LWT へ送られ、Anki 側は何も変更されません。各復習は実際に行われた時点で用語の履歴に加わるため、2 回の取り込みの間に両方のアプリで学習しても、1 つのアプリだけで学習した場合と同じスケジュールになります。何度取り込んでも安全です。LWT に既にある復習はスキップされます。",
+ "anki.sync.error_failed": "同期に失敗しました: {message}",
+ "anki.sync.how_html": "復習は双方向にやり取りされます。各復習は実際に行われた時点で用語の履歴に加わるため、2 回の同期の間に両方のアプリで学習しても、1 つのアプリだけで学習した場合と同じスケジュールになり、その後 Anki のカードに LWT の期日が反映されます。何度同期しても安全です。どちらかに既にある復習はスキップされます。同期されるのは復習とスケジュールだけで、訳語やタグは同期されません。",
"anki.sync.hosted_html": "LWT が別のサーバーで動作している場合、ブラウザーがこのコンピューター上の Anki へのアクセス許可を求めたり、アクセスをブロックしたりすることがあります。このサイトに ローカルネットワークへのアクセス を許可すれば解決します。.apkg ファイルによる往復 はどの環境でも使えます。",
+ "anki.sync.writing": "Anki に書き込み中: {done} / {total}",
+ "anki.sync.pushed_other": "LWT の復習 {count} 件を Anki に送信しました",
+ "anki.sync.cards_other": "Anki のカード {count} 枚に LWT のスケジュールを適用しました",
+ "anki.sync.fsrs_html": "Anki で FSRS を有効にしている場合、Anki はカードごとに独自の記憶の推定値も保持していますが、LWT から送った復習ではこれは更新されません。AnkiConnect では書き込めないためです。期日は正しく設定されます。推定値も合わせるには、Anki のデッキオプションで時々 最適化 を実行してください。",
"titles.terms": "用語",
"titles.term": "用語",
"titles.term_named": "用語:{term}",
@@ -449,5 +453,5 @@
"titles.error": "エラー",
"titles.status_changed": "ステータスを変更しました",
"titles.status_set": "ステータスを設定しました",
- "titles.anki_sync": "Anki から復習を同期"
+ "titles.anki_sync": "Anki と復習を同期"
}
diff --git a/locale/pt/vocabulary.json b/locale/pt/vocabulary.json
index ab4e40734..b66597249 100644
--- a/locale/pt/vocabulary.json
+++ b/locale/pt/vocabulary.json
@@ -435,17 +435,17 @@
"anki.apkg.settings_import": "No sentido inverso, marque Importar qualquer progresso de aprendizagem ao importar um baralho do LWT no Anki, ou o Anki começará cada cartão do zero e descartará o agendamento que esta página exportou.",
"anki.apkg.deck_notice_title": "Vai importar um baralho que você criou no Anki?",
"anki.apkg.deck_notice": "Esta página só atualiza termos que o LWT exportou originalmente — um baralho vindo do Anki ou do AnkiWeb não tem nada aqui com que corresponder, então nada mudaria. Use Importar um baralho do Anki, que cria termos novos e deduz o quanto você conhece cada palavra a partir do próprio agendamento do Anki.",
- "anki.sync.link": "Trazer revisões do Anki (AnkiConnect)",
- "anki.sync.intro": "Traga as revisões que você fez no Anki para o agendamento do LWT, direto do Anki neste computador: nenhum arquivo para exportar ou importar.",
+ "anki.sync.link": "Sincronizar revisões com o Anki (AnkiConnect)",
+ "anki.sync.intro": "Traga para o LWT as revisões que você fez no Anki e envie ao Anki as que fez no LWT, direto do Anki neste computador: nenhum arquivo para exportar ou importar.",
"anki.sync.step_addon_html": "Instale o complemento AnkiConnect e mantenha o Anki aberto.",
"anki.sync.step_export_html": "Seus cartões precisam vir do LWT: exporte-os uma vez com Exportar idioma para pacote Anki (.apkg), para que cada nota leve o seu LwtId.",
"anki.sync.step_open": "Clique no botão abaixo. Na primeira vez, o Anki pergunta se deve confiar nesta página: aceite.",
- "anki.sync.button": "Trazer revisões do Anki",
+ "anki.sync.button": "Sincronizar revisões com o Anki",
"anki.sync.connecting": "Conectando ao Anki...",
"anki.sync.reading_notes": "Lendo notas: {done} de {total}",
"anki.sync.reading_reviews": "Lendo revisões: {done} de {total} cartões",
"anki.sync.sending": "Enviando ao LWT: {done} de {total} revisões",
- "anki.sync.done": "Revisões trazidas do Anki.",
+ "anki.sync.done": "Revisões sincronizadas com o Anki.",
"anki.sync.applied_one": "{count} revisão nova incorporada",
"anki.sync.applied_other": "{count} revisões novas incorporadas",
"anki.sync.terms_one": "{count} termo reagendado",
@@ -458,9 +458,15 @@
"anki.sync.skipped_other": "{count} revisões puladas (termos ignorados, bem conhecidos ou excluídos)",
"anki.sync.error_unreachable": "Não foi possível acessar o Anki em {url}. O Anki está aberto, com o complemento AnkiConnect instalado?",
"anki.sync.error_denied": "O Anki recusou o acesso. Clique no botão novamente e aceite o pedido no Anki.",
- "anki.sync.error_failed": "Falha ao trazer as revisões: {message}",
- "anki.sync.how_html": "Só as revisões viajam, do Anki para o LWT: nada no Anki é alterado. Cada revisão entra no histórico do termo no momento em que aconteceu, então estudar nos dois apps entre duas sincronizações dá o agendamento que você teria em um só. Trazer de novo é seguro: as revisões que o LWT já tem são ignoradas.",
+ "anki.sync.error_failed": "Falha na sincronização: {message}",
+ "anki.sync.how_html": "As revisões viajam nos dois sentidos. Cada uma entra no histórico do termo no momento em que aconteceu, então estudar nos dois apps entre duas sincronizações dá o agendamento que você teria em um só, e os cartões do Anki recebem depois as datas de vencimento do LWT. Sincronizar de novo é seguro: as revisões que qualquer um dos lados já tem são ignoradas. Só revisões e agendamentos são sincronizados, não traduções nem etiquetas.",
"anki.sync.hosted_html": "Se o LWT roda em outro servidor, seu navegador pode pedir permissão para acessar o Anki neste computador, ou bloquear o acesso; permitir o acesso à rede local para este site resolve isso. A troca por arquivo .apkg funciona em qualquer lugar.",
+ "anki.sync.writing": "Gravando no Anki: {done} de {total}",
+ "anki.sync.pushed_one": "{count} revisão do LWT enviada ao Anki",
+ "anki.sync.pushed_other": "{count} revisões do LWT enviadas ao Anki",
+ "anki.sync.cards_one": "{count} cartão do Anki recebeu o agendamento do LWT",
+ "anki.sync.cards_other": "{count} cartões do Anki receberam o agendamento do LWT",
+ "anki.sync.fsrs_html": "Com o FSRS ativado no Anki, o Anki também mantém sua própria estimativa de memória para cada cartão, que as revisões enviadas pelo LWT não atualizam: o AnkiConnect não consegue gravá-la. As datas de vencimento estão certas; para alinhar também as estimativas, execute de vez em quando Otimizar nas opções do baralho do Anki.",
"titles.terms": "Termos",
"titles.term": "Termo",
"titles.term_named": "Termo: {term}",
@@ -471,5 +477,5 @@
"titles.error": "Erro",
"titles.status_changed": "Status alterado",
"titles.status_set": "Status definido",
- "titles.anki_sync": "Sincronizar revisões do Anki"
+ "titles.anki_sync": "Sincronizar revisões com o Anki"
}
diff --git a/locale/ru/vocabulary.json b/locale/ru/vocabulary.json
index a92a7b963..d20658f8c 100644
--- a/locale/ru/vocabulary.json
+++ b/locale/ru/vocabulary.json
@@ -466,17 +466,17 @@
"anki.apkg.settings_import": "В обратную сторону: при импорте колоды LWT в Anki отметьте Импортировать прогресс изучения, иначе Anki начнёт каждую карточку с нуля и отбросит расписание, экспортированное этой страницей.",
"anki.apkg.deck_notice_title": "Импортируете колоду, созданную в Anki?",
"anki.apkg.deck_notice": "Эта страница обновляет только те слова, которые изначально экспортировал LWT: колоде из Anki или AnkiWeb здесь не с чем сопоставляться, поэтому ничего не изменится. Используйте вместо этого импорт колоды Anki — он создаёт новые слова и определяет, насколько хорошо вы знаете каждое из них, по расписанию самого Anki.",
- "anki.sync.link": "Получить повторения из Anki (AnkiConnect)",
- "anki.sync.intro": "Перенесите повторения, сделанные в Anki, в расписание LWT прямо из Anki на этом компьютере: без экспорта и импорта файлов.",
+ "anki.sync.link": "Синхронизировать повторения с Anki (AnkiConnect)",
+ "anki.sync.intro": "Перенесите повторения, сделанные в Anki, в LWT, а сделанные в LWT — в Anki, прямо из Anki на этом компьютере: без экспорта и импорта файлов.",
"anki.sync.step_addon_html": "Установите дополнение AnkiConnect и не закрывайте Anki.",
"anki.sync.step_export_html": "Ваши карточки должны быть из LWT: один раз экспортируйте их через Экспортировать язык в пакет Anki (.apkg), чтобы каждая заметка содержала свой LwtId.",
"anki.sync.step_open": "Нажмите кнопку ниже. В первый раз Anki спросит, доверять ли этой странице: согласитесь.",
- "anki.sync.button": "Получить повторения из Anki",
+ "anki.sync.button": "Синхронизировать повторения с Anki",
"anki.sync.connecting": "Подключение к Anki...",
"anki.sync.reading_notes": "Чтение заметок: {done} из {total}",
"anki.sync.reading_reviews": "Чтение повторений, карточки: {done} из {total}",
"anki.sync.sending": "Отправка повторений в LWT: {done} из {total}",
- "anki.sync.done": "Повторения получены из Anki.",
+ "anki.sync.done": "Повторения синхронизированы с Anki.",
"anki.sync.applied_one": "Добавлено {count} новое повторение",
"anki.sync.applied_few": "Добавлено {count} новых повторения",
"anki.sync.applied_many": "Добавлено {count} новых повторений",
@@ -499,9 +499,19 @@
"anki.sync.skipped_other": "Пропущено {count} повторений (слова игнорируются, хорошо известны или удалены)",
"anki.sync.error_unreachable": "Не удалось связаться с Anki по адресу {url}. Открыт ли Anki и установлено ли дополнение AnkiConnect?",
"anki.sync.error_denied": "Anki отказал в доступе. Нажмите кнопку ещё раз и подтвердите запрос в Anki.",
- "anki.sync.error_failed": "Не удалось получить повторения: {message}",
- "anki.sync.how_html": "Повторения передаются только в одну сторону, из Anki в LWT: в Anki ничего не меняется. Каждое повторение попадает в историю слова в тот момент, когда оно было сделано, поэтому занятия в обоих приложениях между двумя синхронизациями дают то же расписание, что и в одном. Повторная синхронизация безопасна: повторения, которые уже есть в LWT, пропускаются.",
+ "anki.sync.error_failed": "Не удалось выполнить синхронизацию: {message}",
+ "anki.sync.how_html": "Повторения передаются в обе стороны. Каждое попадает в историю слова в тот момент, когда оно было сделано, поэтому занятия в обоих приложениях между двумя синхронизациями дают то же расписание, что и в одном, а карточки Anki затем получают сроки из LWT. Повторная синхронизация безопасна: повторения, которые уже есть на другой стороне, пропускаются. Синхронизируются только повторения и расписания, но не переводы и не метки.",
"anki.sync.hosted_html": "Если LWT работает на другом сервере, браузер может запросить разрешение на доступ к Anki на этом компьютере или заблокировать его; разрешите этому сайту доступ к локальной сети, и всё заработает. Обмен файлами .apkg работает везде.",
+ "anki.sync.writing": "Запись в Anki: {done} из {total}",
+ "anki.sync.pushed_one": "{count} повторение из LWT отправлено в Anki",
+ "anki.sync.pushed_few": "{count} повторения из LWT отправлены в Anki",
+ "anki.sync.pushed_many": "{count} повторений из LWT отправлено в Anki",
+ "anki.sync.pushed_other": "{count} повторений из LWT отправлено в Anki",
+ "anki.sync.cards_one": "Расписание LWT применено к {count} карточке Anki",
+ "anki.sync.cards_few": "Расписание LWT применено к {count} карточкам Anki",
+ "anki.sync.cards_many": "Расписание LWT применено к {count} карточкам Anki",
+ "anki.sync.cards_other": "Расписание LWT применено к {count} карточкам Anki",
+ "anki.sync.fsrs_html": "Если в Anki включён FSRS, Anki также хранит собственную оценку запоминания для каждой карточки, а повторения, отправленные из LWT, её не обновляют: AnkiConnect не может её записать. Сроки повторений верны; чтобы привести в соответствие и оценки, время от времени запускайте Оптимизировать в параметрах колоды Anki.",
"titles.terms": "Слова",
"titles.term": "Слово",
"titles.term_named": "Слово: {term}",
@@ -512,5 +522,5 @@
"titles.error": "Ошибка",
"titles.status_changed": "Статус изменён",
"titles.status_set": "Статус установлен",
- "titles.anki_sync": "Синхронизация повторений из Anki"
+ "titles.anki_sync": "Синхронизация повторений с Anki"
}
diff --git a/locale/zh/vocabulary.json b/locale/zh/vocabulary.json
index 40ff662d8..eb4db991d 100644
--- a/locale/zh/vocabulary.json
+++ b/locale/zh/vocabulary.json
@@ -397,17 +397,17 @@
"anki.apkg.settings_import": "反向操作时,将 LWT 牌组导入 Anki 请勾选 导入学习进度,否则 Anki 会让每张卡片从头开始,并丢弃此页面导出的排程。",
"anki.apkg.deck_notice_title": "要导入您在 Anki 中创建的牌组吗?",
"anki.apkg.deck_notice": "此页面只更新最初由 LWT 导出的词条——来自 Anki 或 AnkiWeb 的牌组在这里没有可匹配的内容,因此不会有任何改变。请改用 导入 Anki 牌组,它会创建新词条,并根据 Anki 自身的排程判断您对每个单词的掌握程度。",
- "anki.sync.link": "从 Anki 拉取复习记录(AnkiConnect)",
- "anki.sync.intro": "直接从本机上的 Anki 将您在 Anki 中完成的复习导入 LWT 的排程:无需导出或导入文件。",
+ "anki.sync.link": "与 Anki 同步复习记录(AnkiConnect)",
+ "anki.sync.intro": "将您在 Anki 中完成的复习导入 LWT,并将您在 LWT 中完成的复习发送到 Anki,直接通过本机上的 Anki 进行:无需导出或导入文件。",
"anki.sync.step_addon_html": "安装 AnkiConnect 插件,并保持 Anki 处于打开状态。",
"anki.sync.step_export_html": "您的卡片必须来自 LWT:先用 将整个语言导出为 Anki 包(.apkg) 导出一次,使每条笔记都带有自己的 LwtId。",
"anki.sync.step_open": "点击下方按钮。首次使用时,Anki 会询问是否信任此页面:请选择接受。",
- "anki.sync.button": "从 Anki 拉取复习记录",
+ "anki.sync.button": "与 Anki 同步复习记录",
"anki.sync.connecting": "正在连接 Anki...",
"anki.sync.reading_notes": "正在读取笔记:{done} / {total}",
"anki.sync.reading_reviews": "正在读取复习记录:{done} / {total} 张卡片",
"anki.sync.sending": "正在发送到 LWT:{done} / {total} 条复习记录",
- "anki.sync.done": "已从 Anki 拉取复习记录。",
+ "anki.sync.done": "复习记录已与 Anki 同步。",
"anki.sync.applied_other": "已合并 {count} 条新复习记录",
"anki.sync.terms_other": "已重新排程 {count} 个词条",
"anki.sync.duplicates_other": "{count} 条复习记录 LWT 中已存在",
@@ -415,9 +415,13 @@
"anki.sync.skipped_other": "已跳过 {count} 条复习记录(词条已忽略、熟知或已删除)",
"anki.sync.error_unreachable": "无法通过 {url} 连接 Anki。Anki 是否已打开,并已安装 AnkiConnect 插件?",
"anki.sync.error_denied": "Anki 拒绝了访问。请再次点击按钮,并在 Anki 中接受请求。",
- "anki.sync.error_failed": "拉取失败:{message}",
- "anki.sync.how_html": "只有复习记录会从 Anki 传到 LWT:Anki 中的内容不会有任何改变。每条复习记录都会按其实际发生的时间加入词条的历史,因此在两次拉取之间同时使用两个应用学习,得到的排程与只用一个应用时相同。重复拉取是安全的:LWT 中已有的复习记录会被跳过。",
+ "anki.sync.error_failed": "同步失败:{message}",
+ "anki.sync.how_html": "复习记录双向传输。每条复习记录都会按其实际发生的时间加入词条的历史,因此在两次同步之间同时使用两个应用学习,得到的排程与只用一个应用时相同,随后 Anki 的卡片会采用 LWT 的到期日期。重复同步是安全的:任一方已有的复习记录会被跳过。只同步复习记录和排程,不同步翻译或标签。",
"anki.sync.hosted_html": "如果 LWT 运行在其他服务器上,浏览器可能会请求访问本机 Anki 的权限,或直接阻止访问;为此网站允许 本地网络访问 即可解决。.apkg 文件往返 在任何环境下都可用。",
+ "anki.sync.writing": "正在写入 Anki:{done} / {total}",
+ "anki.sync.pushed_other": "已将 {count} 条 LWT 复习记录发送到 Anki",
+ "anki.sync.cards_other": "已为 {count} 张 Anki 卡片应用 LWT 的排程",
+ "anki.sync.fsrs_html": "如果在 Anki 中启用了 FSRS,Anki 还会为每张卡片保存自己的记忆估计值,而从 LWT 发送的复习不会更新它:AnkiConnect 无法写入该值。到期日期是正确的;若要让估计值也保持一致,请不时在 Anki 的牌组选项中运行 优化。",
"flash.term_saved": "词条已保存",
"flash.term_updated": "词条已更新",
"flash.term_updated_short": "已更新",
@@ -437,5 +441,5 @@
"titles.error": "错误",
"titles.status_changed": "状态已更改",
"titles.status_set": "状态已设置",
- "titles.anki_sync": "从 Anki 同步复习记录"
+ "titles.anki_sync": "与 Anki 同步复习记录"
}
diff --git a/package.json b/package.json
index f65d5ee1a..288df297a 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,9 @@
"e2e": "cypress run",
"cy:open": "cypress open",
"cy:run": "cypress run",
+ "anki:build": "podman build -t lwt-anki scripts/anki/container",
+ "anki:up": "mkdir -p cypress/anki-exchange && podman run --rm -d --name lwt-anki -p 127.0.0.1:8765:8765 -v ./cypress/anki-exchange:/exchange:Z lwt-anki",
+ "anki:down": "podman stop lwt-anki",
"docs:dev": "node scripts/docs-pre-build.js && vitepress dev docs-src",
"docs:build": "node scripts/docs-pre-build.js && vitepress build docs-src",
"docs:preview": "vitepress preview docs-src"
diff --git a/scripts/anki/container/Containerfile b/scripts/anki/container/Containerfile
new file mode 100644
index 000000000..d803b994b
--- /dev/null
+++ b/scripts/anki/container/Containerfile
@@ -0,0 +1,50 @@
+# Real Anki with AnkiConnect, headless, for testing LWT's Anki sync (#264).
+#
+# podman build -t lwt-anki scripts/anki/container
+# podman run --rm -d --name lwt-anki -p 127.0.0.1:8765:8765 \
+# -v /tmp/lwt-anki-exchange:/exchange:Z lwt-anki
+#
+# Anki runs with Qt's offscreen platform, so no display is needed. Everything
+# comes from first-party sources: Anki from PyPI (published by Ankitects) and
+# AnkiConnect from AnkiWeb, the official add-on channel, checked against a
+# pinned hash. /exchange is where tests put .apkg files for importPackage.
+#
+# Test-only: AnkiConnect binds to every interface inside the container and
+# trusts LWT's dev-server origins, so never publish the port beyond loopback.
+
+FROM docker.io/library/python:3.12-slim-bookworm
+
+ARG ANKI_VERSION=26.9.3
+ARG ANKICONNECT_URL="https://ankiweb.net/shared/download/2055492159?v=2.1&p=260900"
+ARG ANKICONNECT_SHA256=456a546fd9e1bf53962c70618f7d72d10b1768690ce88fa5c9c6909ae5e9e1ec
+
+# Qt 6's runtime libraries; the offscreen platform still loads GL and fonts.
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ ca-certificates curl \
+ libgl1 libegl1 libopengl0 libxkbcommon0 libfontconfig1 libfreetype6 \
+ libdbus-1-3 libglib2.0-0 libnss3 libasound2 libgbm1 libxshmfence1 \
+ libxcomposite1 libxdamage1 libxrandr2 libxtst6 libxkbfile1 libxi6 \
+ libxrender1 libxcursor1 libxcb-cursor0 fonts-dejavu-core \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN pip install --no-cache-dir "aqt[qt6]==${ANKI_VERSION}"
+
+RUN useradd --create-home anki && mkdir /exchange && chown anki /exchange
+USER anki
+ENV ANKI_BASE=/home/anki/anki \
+ QT_QPA_PLATFORM=offscreen \
+ QTWEBENGINE_CHROMIUM_FLAGS=--no-sandbox \
+ PYTHONUNBUFFERED=1
+
+RUN mkdir -p "$ANKI_BASE/addons21/2055492159" \
+ && curl -fsSL -o /tmp/ankiconnect.zip "$ANKICONNECT_URL" \
+ && echo "$ANKICONNECT_SHA256 /tmp/ankiconnect.zip" | sha256sum -c - \
+ && python -m zipfile -e /tmp/ankiconnect.zip "$ANKI_BASE/addons21/2055492159" \
+ && rm /tmp/ankiconnect.zip
+
+COPY --chown=anki ankiconnect-meta.json /home/anki/anki/addons21/2055492159/meta.json
+COPY --chown=anki start.py /home/anki/start.py
+
+EXPOSE 8765
+CMD ["python", "/home/anki/start.py"]
diff --git a/scripts/anki/container/ankiconnect-meta.json b/scripts/anki/container/ankiconnect-meta.json
new file mode 100644
index 000000000..641bdb9f0
--- /dev/null
+++ b/scripts/anki/container/ankiconnect-meta.json
@@ -0,0 +1,14 @@
+{
+ "config": {
+ "apiKey": null,
+ "apiLogPath": null,
+ "webBindAddress": "0.0.0.0",
+ "webBindPort": 8765,
+ "webCorsOriginList": [
+ "http://localhost",
+ "http://localhost:8000",
+ "http://127.0.0.1:8000"
+ ],
+ "ignoreOriginList": []
+ }
+}
diff --git a/scripts/anki/container/start.py b/scripts/anki/container/start.py
new file mode 100644
index 000000000..581052c53
--- /dev/null
+++ b/scripts/anki/container/start.py
@@ -0,0 +1,62 @@
+"""Start headless Anki with one ready profile, so AnkiConnect comes up unattended.
+
+A first launch would stop at Anki's language and profile dialogs, which nobody
+can answer offscreen. Creating the profile beforehand through Anki's own
+ProfileManager skips them; after that this is a plain `anki -b BASE -p PROFILE`.
+"""
+
+from __future__ import annotations
+
+import os
+import sys
+from pathlib import Path
+
+BASE = Path(os.environ.get("ANKI_BASE", "/home/anki/anki"))
+PROFILE = os.environ.get("ANKI_PROFILE", "User 1")
+
+
+def ensure_profile() -> None:
+ if (BASE / "prefs21.db").exists():
+ return
+
+ from aqt.profiles import ProfileManager
+
+ manager = ProfileManager(BASE)
+ manager.setupMeta()
+ manager.setLang("en_US")
+ manager.create(PROFILE)
+
+
+def set_scheduler() -> None:
+ """Switch FSRS on or off when ANKI_FSRS says so (1 / 0); leave it alone otherwise.
+
+ Anki's default is off, and AnkiConnect cannot change it, so tests of the
+ FSRS case set it here, before Anki holds the collection open.
+ """
+ wanted = os.environ.get("ANKI_FSRS")
+ if wanted not in ("0", "1"):
+ return
+
+ from anki.collection import Collection
+
+ (BASE / PROFILE).mkdir(parents=True, exist_ok=True)
+ col = Collection(str(BASE / PROFILE / "collection.anki2"))
+ try:
+ col.set_config("fsrs", wanted == "1")
+ finally:
+ col.close()
+
+
+def main() -> None:
+ BASE.mkdir(parents=True, exist_ok=True)
+ ensure_profile()
+ set_scheduler()
+
+ import aqt
+
+ sys.argv = ["anki", "-b", str(BASE), "-p", PROFILE]
+ aqt.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/Modules/Vocabulary/Application/Services/Anki/AnkiPushPlan.php b/src/Modules/Vocabulary/Application/Services/Anki/AnkiPushPlan.php
new file mode 100644
index 000000000..817be8052
--- /dev/null
+++ b/src/Modules/Vocabulary/Application/Services/Anki/AnkiPushPlan.php
@@ -0,0 +1,210 @@
+
+ * @link https://github.com/HugoFara/lwt
+ */
+
+declare(strict_types=1);
+
+namespace Lwt\Modules\Vocabulary\Application\Services\Anki;
+
+use DateTimeImmutable;
+use Lwt\Modules\Review\Domain\Scheduling\HistoricReview;
+use Lwt\Modules\Review\Domain\Scheduling\Rating;
+use Lwt\Modules\Review\Domain\TermScheduleRepositoryInterface;
+use Lwt\Modules\Review\Infrastructure\MySqlTermScheduleRepository;
+use Lwt\Modules\Vocabulary\Domain\TermRepositoryInterface;
+use Lwt\Modules\Vocabulary\Infrastructure\MySqlTermRepository;
+
+/**
+ * The server half of pushing reviews to Anki (#264, step 2).
+ *
+ * Runs after a pull, so LWT's history already holds every review from both
+ * apps. For each Anki card, the browser sends the reviews Anki has; this
+ * answers with what Anki is missing, as AnkiConnect calls for the browser to
+ * make:
+ *
+ * - `insertReviews` rows for LWT reviews absent from the card's revlog,
+ * shaped exactly as the .apkg exporter writes them (ApkgWriter);
+ * - the card's due date (`setDueDate`) and its interval, reps and lapses
+ * (`setSpecificValueOfCard`), so Anki's next session agrees with LWT.
+ *
+ * Measured against Anki 26.9 with AnkiConnect: `insertReviews` only appends
+ * history, leaving the card untouched, so the schedule has to be set
+ * separately; and AnkiConnect refuses to write FSRS memory state at all. With
+ * FSRS on, Anki's memory state therefore lags until the learner reoptimises,
+ * which recomputes it from the history this sends (see the sync doc).
+ *
+ * Cards whose history Anki already has get no action, so a second push right
+ * after the first plans nothing.
+ */
+final class AnkiPushPlan
+{
+ /** Anki's default ease factor, in permille, as ApkgWriter writes it. */
+ private const DEFAULT_EASE_FACTOR = 2500;
+
+ /** revlog.type for a review-stage answer, as ApkgWriter writes it. */
+ private const REVLOG_TYPE_REVIEW = 1;
+
+ /** Most cards accepted in one request. */
+ public const MAX_CARDS = 2000;
+
+ public function __construct(
+ private readonly TermRepositoryInterface $terms,
+ private readonly TermScheduleRepositoryInterface $schedules,
+ ) {
+ }
+
+ public static function default(): self
+ {
+ return new self(new MySqlTermRepository(), new MySqlTermScheduleRepository());
+ }
+
+ /**
+ * Plan the writes that bring Anki up to LWT for these cards.
+ *
+ * @param list