feat(deck): add daily learning limits and today's study stats

- Add newPerDay and revPerDay fields to Deck model (Anki-style)
- Add settings modal to configure daily limits per deck
- Display today's studied counts (new/review/learning) on deck page
- Add i18n translations for all 8 languages
- Fix JSON syntax errors in fr-FR.json and it-IT.json
- Fix double counting bug in repoGetTodayStudyStats
This commit is contained in:
2026-03-16 09:01:55 +08:00
parent a68951f1d3
commit bc0b392875
23 changed files with 466 additions and 60 deletions

View File

@@ -517,6 +517,18 @@
"resetSuccess": "{count} Karten erfolgreich zurückgesetzt",
"resetting": "Wird zurückgesetzt...",
"cancel": "Abbrechen",
"settings": "Einstellungen",
"settingsTitle": "Deck-Einstellungen",
"newPerDay": "Neue Karten pro Tag",
"newPerDayHint": "Maximale Anzahl neuer Karten pro Tag",
"revPerDay": "Wiederholungen pro Tag",
"revPerDayHint": "Maximale Anzahl wiederholter Karten pro Tag",
"save": "Speichern",
"saving": "Wird gespeichert...",
"settingsSaved": "Einstellungen gespeichert",
"todayNew": "Neu",
"todayReview": "Wiederholung",
"todayLearning": "Lernen",
"error": {
"update": "Sie haben keine Berechtigung, diese Karte zu aktualisieren.",
"delete": "Sie haben keine Berechtigung, diese Karte zu löschen.",

View File

@@ -103,6 +103,18 @@
"resetSuccess": "Successfully reset {count} cards",
"resetting": "Resetting...",
"cancel": "Cancel",
"settings": "Settings",
"settingsTitle": "Deck Settings",
"newPerDay": "New Cards Per Day",
"newPerDayHint": "Maximum new cards to learn each day",
"revPerDay": "Review Cards Per Day",
"revPerDayHint": "Maximum review cards each day",
"save": "Save",
"saving": "Saving...",
"settingsSaved": "Settings saved",
"todayNew": "New",
"todayReview": "Review",
"todayLearning": "Learning",
"error": {
"update": "You do not have permission to update this card.",
"delete": "You do not have permission to delete this card.",

View File

@@ -112,47 +112,25 @@
"resetSuccess": "{count} cartes réinitialisées avec succès",
"resetting": "Réinitialisation en cours...",
"cancel": "Annuler",
"settings": "Paramètres",
"settingsTitle": "Paramètres du deck",
"newPerDay": "Nouvelles cartes par jour",
"newPerDayHint": "Nombre maximum de nouvelles cartes par jour",
"revPerDay": "Révisions par jour",
"revPerDayHint": "Nombre maximum de cartes à réviser par jour",
"save": "Enregistrer",
"saving": "Enregistrement...",
"settingsSaved": "Paramètres enregistrés",
"todayNew": "Nouvelles",
"todayReview": "Révisions",
"todayLearning": "En cours",
"error": {
"update": "Vous n'avez pas la permission de mettre à jour cette carte.",
"delete": "Vous n'avez pas la permission de supprimer cette carte.",
"add": "Vous n'avez pas la permission d'ajouter des cartes à ce deck."
}
},
"deck_id": {
"unauthorized": "Vous n'êtes pas le propriétaire de ce paquet",
"back": "Retour",
"cards": "Cartes",
"itemsCount": "{count} éléments",
"memorize": "Mémoriser",
"loadingCards": "Chargement des cartes...",
"noCards": "Aucune carte dans ce paquet",
"card": "Carte",
"addNewCard": "Ajouter une nouvelle carte",
"add": "Ajouter",
"adding": "Ajout en cours...",
"updateCard": "Mettre à jour la carte",
"update": "Mettre à jour",
"updating": "Mise à jour en cours...",
"word": "Mot",
"definition": "Définition",
"ipa": "IPA",
"example": "Exemple",
"wordAndDefinitionRequired": "Le mot et la définition sont requis",
"edit": "Modifier",
"delete": "Supprimer",
"permissionDenied": "Vous n'avez pas la permission d'effectuer cette action",
"resetProgress": "Réinitialiser",
"resetProgressTitle": "Réinitialiser la progression du paquet",
"resetProgressConfirm": "Cela réinitialisera toutes les cards in this deck to new state. Your learning progress will be lost. Are you sure?",
"resetSuccess": "{count} cards réinitialisées avec succès",
"resetting": "Réinitialisation en cours...",
"cancel": "Annuler",
"error": {
"update": "Vous n'avez pas la permission de mettre à jour cette carte.",
"delete": "Vous n'avez pas la permission de supprimer cette carte.",
"add": "Vous n'avez pas la permission d'ajouter des cartes à ce paquet."
}
},
"home": {
"title": "Apprendre les langues",
"description": "Voici un site Web très utile pour vous aider à apprendre presque toutes les langues du monde, y compris les langues construites.",
"explore": "Explorer",

View File

@@ -112,12 +112,25 @@
"resetSuccess": "{count} tarjetas ripristinate exitosamente",
"resetting": "Ripristazione en curso...",
"cancel": "Annulla",
"settings": "Impostazioni",
"settingsTitle": "Impostazioni deck",
"newPerDay": "Nuove schede al giorno",
"newPerDayHint": "Numero massimo di nuove schede al giorno",
"revPerDay": "Ripassi al giorno",
"revPerDayHint": "Numero massimo di schede da ripassare al giorno",
"save": "Salva",
"saving": "Salvataggio...",
"settingsSaved": "Impostazioni salvate",
"todayNew": "Nuove",
"todayReview": "Ripasso",
"todayLearning": "In corso",
"error": {
"update": "Non hai il permesso per aggiorn this card.",
"delete": "Non hai il permesso per delete this card.",
"add": "Non hai il permesso per add cards to this deck."
}
},
"home": {
"title": "Impara le Lingue",
"description": "Ecco un sito molto utile per aiutarti a imparare quasi tutte le lingue del mondo, incluse quelle costruite.",
"explore": "Esplora",

View File

@@ -103,6 +103,18 @@
"resetSuccess": "{count}枚のカードを正常にリセットしました",
"resetting": "リセット中...",
"cancel": "キャンセル",
"settings": "設定",
"settingsTitle": "デッキ設定",
"newPerDay": "1日の新規カード数",
"newPerDayHint": "1日に学習する新規カードの最大数",
"revPerDay": "1日の復習カード数",
"revPerDayHint": "1日に復習するカードの最大数",
"save": "保存",
"saving": "保存中...",
"settingsSaved": "設定を保存しました",
"todayNew": "新規",
"todayReview": "復習",
"todayLearning": "学習中",
"error": {
"update": "このカードを更新する権限がありません。",
"delete": "このカードを削除する権限がありません。",

View File

@@ -83,6 +83,53 @@
"deleteFolder": "이 폴더를 삭제할 권한이 없습니다."
}
},
"deck_id": {
"unauthorized": "이 덱의 소유자가 아닙니다",
"back": "뒤로",
"cards": "카드",
"itemsCount": "{count}개",
"memorize": "암기",
"loadingCards": "카드 불러오는 중...",
"noCards": "이 덱에 카드가 없습니다",
"card": "카드",
"addNewCard": "새 카드 추가",
"add": "추가",
"adding": "추가 중...",
"updateCard": "카드 업데이트",
"update": "업데이트",
"updating": "업데이트 중...",
"word": "단어",
"definition": "정의",
"ipa": "IPA",
"example": "예문",
"wordAndDefinitionRequired": "단어와 정의는 필수입니다",
"edit": "편집",
"delete": "삭제",
"permissionDenied": "이 작업을 수행할 권한이 없습니다",
"resetProgress": "초기화",
"resetProgressTitle": "덱 진행 초기화",
"resetProgressConfirm": "이 덱의 모든 카드가 새 상태로 초기화됩니다. 학습 진행 상황이 손실됩니다. 계속하시겠습니까?",
"resetSuccess": "{count}개 카드 초기화 완료",
"resetting": "초기화 중...",
"cancel": "취소",
"settings": "설정",
"settingsTitle": "덱 설정",
"newPerDay": "하루 새 카드 수",
"newPerDayHint": "하루에 학습할 최대 새 카드 수",
"revPerDay": "하루 복습 카드 수",
"revPerDayHint": "하루에 복습할 최대 카드 수",
"save": "저장",
"saving": "저장 중...",
"settingsSaved": "설정 저장됨",
"todayNew": "새 카드",
"todayReview": "복습",
"todayLearning": "학습 중",
"error": {
"update": "이 카드를 업데이트할 권한이 없습니다.",
"delete": "이 카드를 삭제할 권한이 없습니다.",
"add": "이 덱에 카드를 추가할 권한이 없습니다."
}
},
"home": {
"title": "언어 배우기",
"description": "세계의 거의 모든 언어(인공어 포함)를 배우는 데 도움이 되는 매우 유용한 웹사이트입니다.",

View File

@@ -83,6 +83,53 @@
"deleteFolder": "بۇ قىسقۇچنى ئۆچۈرۈش ھوقۇقىڭىز يوق."
}
},
"deck_id": {
"unauthorized": "بۇ دېكنىڭ ئىگىسى ئەمەس",
"back": "قايتىش",
"cards": "كارتلار",
"itemsCount": "{count} تۈر",
"memorize": "يادلاش",
"loadingCards": "كارتلار يۈكلىنىۋاتىدۇ...",
"noCards": "بۇ دېكتا كارت يوق",
"card": "كارتا",
"addNewCard": "يېڭى كارتا قوشۇش",
"add": "قوشۇش",
"adding": "قوشۇلىۋاتىدۇ...",
"updateCard": "كارتىنى يېڭىلاش",
"update": "يېڭىلاش",
"updating": "يېڭىلىنىۋاتىدۇ...",
"word": "سۆز",
"definition": "ئېنىقلىما",
"ipa": "IPA",
"example": "مىسال",
"wordAndDefinitionRequired": "سۆز ۋە ئېنىقلىما زۆرۈر",
"edit": "تەھرىرلەش",
"delete": "ئۆچۈرۈش",
"permissionDenied": "بۇ مەشغۇلاتنى ئېلىپ بېرىش ھوقۇقىڭىز يوق",
"resetProgress": "قايتا تەڭشەش",
"resetProgressTitle": "دېك ئىلگىرىلەش قايتا تەڭشەش",
"resetProgressConfirm": "بۇ دېكتىكى بارلىق كارتىلار يېڭى ھالەتكە قايتا تەڭشىلىدۇ. ئۆگىنىش ئىلگىرىلەشلىرىڭىز يوقىلىدۇ. داۋاملاشتۇرامسىز؟",
"resetSuccess": "{count} كارتا مۇۋەپپەقىيەتلىك قايتا تەڭشەلدى",
"resetting": "قايتا تەڭشەۋاتىدۇ...",
"cancel": "بىكار قىلىش",
"settings": "تەڭشەكلەر",
"settingsTitle": "دېك تەڭشەكلىرى",
"newPerDay": "كۈندىلىك يېڭى كارتا سانى",
"newPerDayHint": "ھەر كۈنى ئۆگىنىدىغان ئەڭ كۆپ يېڭى كارتا سانى",
"revPerDay": "كۈندىلىك تەكرار سانى",
"revPerDayHint": "ھەر كۈنى تەكرارلايدىغان ئەڭ كۆپ كارتا سانى",
"save": "ساقلاش",
"saving": "ساقلىنىۋاتىدۇ...",
"settingsSaved": "تەڭشەكلەر ساقلاندى",
"todayNew": "يېڭى",
"todayReview": "تەكرار",
"todayLearning": "ئۆگىنىۋاتىدۇ",
"error": {
"update": "بۇ كارتىنى يېڭىلاش ھوقۇقىڭىز يوق.",
"delete": "بۇ كارتىنى ئۆچۈرۈش ھوقۇقىڭىز يوق.",
"add": "بۇ دېككە كارتا قوشۇش ھوقۇقىڭىز يوق."
}
},
"home": {
"title": "تىل ئۆگىنىش",
"description": "بۇ دۇنيادىكى almost ھەر بىر تىلنى، جۈملىدىن سۈنئىي تىللارنى ئۆگىنىشىڭىزگە ياردەم بېرىدىغان ئىنتايىن قوللىنىشلىق تور بېكەت.",

View File

@@ -103,6 +103,18 @@
"resetSuccess": "成功重置 {count} 张卡片",
"resetting": "重置中...",
"cancel": "取消",
"settings": "设置",
"settingsTitle": "牌组设置",
"newPerDay": "每日新卡数量",
"newPerDayHint": "每天最多学习的新卡片数量",
"revPerDay": "每日复习数量",
"revPerDayHint": "每天最多复习的卡片数量",
"save": "保存",
"saving": "保存中...",
"settingsSaved": "设置已保存",
"todayNew": "新卡",
"todayReview": "复习",
"todayLearning": "学习中",
"error": {
"update": "您没有权限更新此卡片",
"delete": "您没有权限删除此卡片",