forked from akai/readest
feat(annotation): export annotations with style and color fields in annotation template, closes #1734 (#3060)
This commit is contained in:
@@ -125,6 +125,7 @@
|
||||
"marked": "^15.0.12",
|
||||
"nanoid": "^5.1.6",
|
||||
"next": "16.0.10",
|
||||
"nunjucks": "^3.2.4",
|
||||
"overlayscrollbars": "^2.11.4",
|
||||
"overlayscrollbars-react": "^0.5.6",
|
||||
"posthog-js": "^1.246.0",
|
||||
@@ -158,6 +159,7 @@
|
||||
"@types/cssbeautify": "^0.3.5",
|
||||
"@types/lunr": "^2.3.7",
|
||||
"@types/node": "^22.15.31",
|
||||
"@types/nunjucks": "^3.2.6",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-color": "^3.0.13",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
|
||||
@@ -914,7 +914,6 @@
|
||||
"Array of annotations": "مصفوفة التعليقات",
|
||||
"Highlighted text": "النص المميز",
|
||||
"Annotation note": "ملاحظة التعليق",
|
||||
"Update time": "وقت التحديث",
|
||||
"Date Format Tokens:": "رموز تنسيق التاريخ:",
|
||||
"Year (4 digits)": "السنة (4 أرقام)",
|
||||
"Month (01-12)": "الشهر (01-12)",
|
||||
@@ -932,5 +931,50 @@
|
||||
"Show on Discord": "عرض على Discord",
|
||||
"Instant {{action}}": "{{action}} فوري",
|
||||
"Instant {{action}} Disabled": "تم تعطيل {{action}} فوري",
|
||||
"Annotation": "التعليق"
|
||||
"Annotation": "التعليق",
|
||||
"Reset Template": "إعادة تعيين القالب",
|
||||
"Annotation style": "نمط التعليق",
|
||||
"Annotation color": "لون التعليق",
|
||||
"Annotation time": "وقت التعليق",
|
||||
"AI": "الذكاء الاصطناعي",
|
||||
"Are you sure you want to re-index this book?": "هل أنت متأكد من إعادة فهرسة هذا الكتاب؟",
|
||||
"Enable AI in Settings": "تفعيل الذكاء الاصطناعي في الإعدادات",
|
||||
"Index This Book": "فهرسة هذا الكتاب",
|
||||
"Enable AI search and chat for this book": "تفعيل البحث والدردشة بالذكاء الاصطناعي لهذا الكتاب",
|
||||
"Start Indexing": "بدء الفهرسة",
|
||||
"Indexing book...": "جاري فهرسة الكتاب...",
|
||||
"Preparing...": "جاري التحضير...",
|
||||
"Delete this conversation?": "حذف هذه المحادثة؟",
|
||||
"No conversations yet": "لا توجد محادثات بعد",
|
||||
"Start a new chat to ask questions about this book": "ابدأ محادثة جديدة لطرح أسئلة حول هذا الكتاب",
|
||||
"Rename": "إعادة التسمية",
|
||||
"New Chat": "محادثة جديدة",
|
||||
"Chat": "محادثة",
|
||||
"Please enter a model ID": "الرجاء إدخال معرف النموذج",
|
||||
"Model not available or invalid": "النموذج غير متاح أو غير صالح",
|
||||
"Failed to validate model": "فشل التحقق من النموذج",
|
||||
"Couldn't connect to Ollama. Is it running?": "تعذر الاتصال بـ Ollama. هل يعمل؟",
|
||||
"Invalid API key or connection failed": "مفتاح API غير صالح أو فشل الاتصال",
|
||||
"Connection failed": "فشل الاتصال",
|
||||
"AI Assistant": "مساعد الذكاء الاصطناعي",
|
||||
"Enable AI Assistant": "تفعيل مساعد الذكاء الاصطناعي",
|
||||
"Provider": "المزود",
|
||||
"Ollama (Local)": "Ollama (محلي)",
|
||||
"AI Gateway (Cloud)": "بوابة الذكاء الاصطناعي (سحابي)",
|
||||
"Ollama Configuration": "إعدادات Ollama",
|
||||
"Refresh Models": "تحديث النماذج",
|
||||
"AI Model": "نموذج الذكاء الاصطناعي",
|
||||
"No models detected": "لم يتم اكتشاف نماذج",
|
||||
"AI Gateway Configuration": "إعدادات بوابة الذكاء الاصطناعي",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "اختر من مجموعة من نماذج الذكاء الاصطناعي عالية الجودة والاقتصادية. يمكنك أيضًا استخدام نموذجك الخاص بتحديد \"نموذج مخصص\" أدناه.",
|
||||
"API Key": "مفتاح API",
|
||||
"Get Key": "احصل على المفتاح",
|
||||
"Model": "النموذج",
|
||||
"Custom Model...": "نموذج مخصص...",
|
||||
"Custom Model ID": "معرف النموذج المخصص",
|
||||
"Validate": "تحقق",
|
||||
"Model available": "النموذج متاح",
|
||||
"Connection": "الاتصال",
|
||||
"Test Connection": "اختبار الاتصال",
|
||||
"Connected": "متصل"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "টীকাগুলির তালিকা",
|
||||
"Highlighted text": "হাইলাইট করা পাঠ্য",
|
||||
"Annotation note": "টীকা নোট",
|
||||
"Update time": "আপডেট সময়",
|
||||
"Date Format Tokens:": "তারিখ বিন্যাস টোকেন:",
|
||||
"Year (4 digits)": "বছর (4 সংখ্যা)",
|
||||
"Month (01-12)": "মাস (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Discord-এ দেখান",
|
||||
"Instant {{action}}": "তাৎক্ষণিক {{action}}",
|
||||
"Instant {{action}} Disabled": "তাৎক্ষণিক {{action}} নিষ্ক্রিয়",
|
||||
"Annotation": "টীকা"
|
||||
"Annotation": "টীকা",
|
||||
"Reset Template": "টেমপ্লেট রিসেট করুন",
|
||||
"Annotation style": "টীকা শৈলী",
|
||||
"Annotation color": "টীকা রঙ",
|
||||
"Annotation time": "টীকা সময়",
|
||||
"AI": "কৃত্রিম বুদ্ধিমত্তা (AI)",
|
||||
"Are you sure you want to re-index this book?": "আপনি কি নিশ্চিত যে আপনি এই বইটি পুনরায় ইনডেক্স করতে চান?",
|
||||
"Enable AI in Settings": "সেটিংস থেকে AI সক্রিয় করুন",
|
||||
"Index This Book": "এই বইটি ইনডেক্স করুন",
|
||||
"Enable AI search and chat for this book": "এই বইটির জন্য AI অনুসন্ধান এবং চ্যাট সক্রিয় করুন",
|
||||
"Start Indexing": "ইনডেক্সিং শুরু করুন",
|
||||
"Indexing book...": "বই ইনডেক্স করা হচ্ছে...",
|
||||
"Preparing...": "প্রস্তুত করা হচ্ছে...",
|
||||
"Delete this conversation?": "এই কথোপকথনটি মুছবেন?",
|
||||
"No conversations yet": "এখনও কোনও কথোপকথন নেই",
|
||||
"Start a new chat to ask questions about this book": "এই বইটি সম্পর্কে প্রশ্ন জিজ্ঞাসা করতে একটি নতুন চ্যাট শুরু করুন",
|
||||
"Rename": "নাম পরিবর্তন",
|
||||
"New Chat": "নতুন চ্যাট",
|
||||
"Chat": "চ্যাট",
|
||||
"Please enter a model ID": "দয়া করে একটি মডেল আইডি লিখুন",
|
||||
"Model not available or invalid": "মডেল উপলব্ধ নয় বা অবৈধ",
|
||||
"Failed to validate model": "মডেল যাচাই করতে ব্যর্থ হয়েছে",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollama এর সাথে সংযোগ করা যায়নি। এটি কি চলছে?",
|
||||
"Invalid API key or connection failed": "অবৈধ API কী বা সংযোগ ব্যর্থ হয়েছে",
|
||||
"Connection failed": "সংযোগ ব্যর্থ হয়েছে",
|
||||
"AI Assistant": "AI সহকারী",
|
||||
"Enable AI Assistant": "AI সহকারী সক্রিয় করুন",
|
||||
"Provider": "প্রদানকারী",
|
||||
"Ollama (Local)": "Ollama (স্থানীয়)",
|
||||
"AI Gateway (Cloud)": "AI গেটওয়ে (ক্লাউড)",
|
||||
"Ollama Configuration": "Ollama কনফিগারেশন",
|
||||
"Refresh Models": "মডেল রিফ্রেশ করুন",
|
||||
"AI Model": "AI মডেল",
|
||||
"No models detected": "কোনও মডেল শনাক্ত করা যায়নি",
|
||||
"AI Gateway Configuration": "AI গেটওয়ে কনফিগারেশন",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "উচ্চ-মানের, সাশ্রয়ী AI মডেলগুলি থেকে নির্বাচন করুন। আপনি নিচে \"কাস্টম মডেল\" নির্বাচন করে আপনার নিজস্ব মডেলও আনতে পারেন।",
|
||||
"API Key": "API কী",
|
||||
"Get Key": "কী পান",
|
||||
"Model": "মডেল",
|
||||
"Custom Model...": "কাস্টম মডেল...",
|
||||
"Custom Model ID": "কাস্টম মডেল আইডি",
|
||||
"Validate": "যাচাই করুন",
|
||||
"Model available": "মডেল উপলব্ধ",
|
||||
"Connection": "সংযোগ",
|
||||
"Test Connection": "সংযোগ পরীক্ষা করুন",
|
||||
"Connected": "সংযুক্ত"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "གསལ་བཤད་ལེབ་ངོས།",
|
||||
"Highlighted text": "གཙོ་གནད་ཡིག་རྐྱང་།",
|
||||
"Annotation note": "གསལ་བཤད་ཟིན་བྲིས།",
|
||||
"Update time": "གསར་བཅོས་དུས་ཚོད།",
|
||||
"Date Format Tokens:": "ཚེས་གྲངས་རྣམ་གཞག་རྟགས།:",
|
||||
"Year (4 digits)": "ལོ། (གྲངས་ཐང་4)",
|
||||
"Month (01-12)": "ཟླ། (01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "Discord ཐོག་སྟོན།",
|
||||
"Instant {{action}}": "འཕྲལ་མར་{{action}}",
|
||||
"Instant {{action}} Disabled": "འཕྲལ་མར་{{action}}་ལྕོགས་མིན་བཟོས།",
|
||||
"Annotation": "མཆན་འགྲེལ།"
|
||||
"Annotation": "མཆན་འགྲེལ།",
|
||||
"Reset Template": "དཔེ་གཞི་བསྐྱར་སྒྲིག",
|
||||
"Annotation style": "མཆན་འགྲེལ་གྱི་བཟོ་ལྟ།",
|
||||
"Annotation color": "མཆན་འགྲེལ་གྱི་ཚོན་མདོག",
|
||||
"Annotation time": "མཆན་འགྲེལ་གྱི་དུས་ཚོད།",
|
||||
"AI": "རིག་ནུས་མིས་བཟོས། (AI)",
|
||||
"Are you sure you want to re-index this book?": "ཁྱེད་ཀྱིས་དཔེ་དེབ་འདི་བསྐྱར་དུ་དཀར་ཆག་བཟོ་རྒྱུ་གཏན་འཁེལ་ཡིན་ནམ།",
|
||||
"Enable AI in Settings": "སྒྲིག་བཀོད་ནང་ AI སྤྱོད་པར་བྱོས།",
|
||||
"Index This Book": "དཔེ་དེབ་འདི་དཀར་ཆག་བཟོ་བ།",
|
||||
"Enable AI search and chat for this book": "དཔེ་དེབ་འདིར་ AI འཚོལ་བཤེར་དང་ཁ་བརྡ་སྤྱོད་པར་བྱོས།",
|
||||
"Start Indexing": "དཀར་ཆག་བཟོ་འགོ་བཙུགས་པ།",
|
||||
"Indexing book...": "དཔེ་དེབ་དཀར་ཆག་བཟོ་བཞིན་པ།...",
|
||||
"Preparing...": "གྲ་སྒྲིག་བྱེད་བཞིན་པ།...",
|
||||
"Delete this conversation?": "ཁ་བརྡ་འདི་བསུབ་དགོས་སམ།",
|
||||
"No conversations yet": "ད་ལྟའི་བར་ཁ་བརྡ་མེད།",
|
||||
"Start a new chat to ask questions about this book": "དཔེ་དེབ་འདིའི་སྐོར་ལ་དྲི་བ་དྲི་བར་ཁ་བརྡ་གསར་པ་ཞིག་འགོ་བཙུགས་པ།",
|
||||
"Rename": "མིང་བརྗེ་བ།",
|
||||
"New Chat": "ཁ་བརྡ་གསར་པ།",
|
||||
"Chat": "ཁ་བརྡ།",
|
||||
"Please enter a model ID": "དཔེ་གཞིའི་ཨང་རྟགས་ནང་འཇུག་བྱོས།",
|
||||
"Model not available or invalid": "དཔེ་གཞི་མེད་པ་འམ་ནུས་མེད།",
|
||||
"Failed to validate model": "དཔེ་གཞི་བདེན་སྦྱོར་བྱེད་ཐུབ་མེད།",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollama ལ་འབྲེལ་མཐུད་བྱེད་ཐུབ་མེད། དེ་འཁོར་བཞིན་ཡོད་དམ།",
|
||||
"Invalid API key or connection failed": "API ལྡེ་མིག་ནུས་མེད་དམ་འབྲེལ་མཐུད་ཕམ་པ།",
|
||||
"Connection failed": "འབྲེལ་མཐུད་ཕམ་པ།",
|
||||
"AI Assistant": "AI རོགས་པ།",
|
||||
"Enable AI Assistant": "AI རོགས་པ་སྤྱོད་པར་བྱོས།",
|
||||
"Provider": "མཁོ་འདོན་པ།",
|
||||
"Ollama (Local)": "Ollama (ས་གནས།)",
|
||||
"AI Gateway (Cloud)": "AI འཛུལ་སྒོ། (སྤྲིན་གནས།)",
|
||||
"Ollama Configuration": "Ollama སྒྲིག་བཀོད།",
|
||||
"Refresh Models": "དཔེ་གཞི་བསྐྱར་བརྗེ།",
|
||||
"AI Model": "AI དཔེ་གཞི།",
|
||||
"No models detected": "དཔེ་གཞི་མ་རྙེད།",
|
||||
"AI Gateway Configuration": "AI འཛུལ་སྒོའི་སྒྲིག་བཀོད།",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "སྤུས་ལེགས་དང་ཁེ་ཕན་ཆེ་བའི་ AI དཔེ་གཞི་འདེམས་དགོས། ཁྱེད་ཀྱིས་འོག་གི་ \"རང་བཟོའི་དཔེ་གཞི།\" བདམས་ནས་རང་གི་དཔེ་གཞི་བེད་སྤྱོད་ཀྱང་ཆོག",
|
||||
"API Key": "API ལྡེ་མིག་",
|
||||
"Get Key": "ལྡེ་མིག་ལེན་པ།",
|
||||
"Model": "དཔེ་གཞི།",
|
||||
"Custom Model...": "རང་བཟོའི་དཔེ་གཞི།...",
|
||||
"Custom Model ID": "རང་བཟོའི་དཔེ་གཞིའི་ཨང་རྟགས།",
|
||||
"Validate": "བདེན་སྦྱོར།",
|
||||
"Model available": "དཔེ་གཞི་ཡོད།",
|
||||
"Connection": "འབྲེལ་མཐུད།",
|
||||
"Test Connection": "འབྲེལ་མཐུད་ཚོད་ལྟ།",
|
||||
"Connected": "འབྲེལ་མཐུད་ཟིན།"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "Array von Anmerkungen",
|
||||
"Highlighted text": "Markierter Text",
|
||||
"Annotation note": "Anmerkungsnotiz",
|
||||
"Update time": "Aktualisierungszeit",
|
||||
"Date Format Tokens:": "Datumsformat-Token:",
|
||||
"Year (4 digits)": "Jahr (4 Ziffern)",
|
||||
"Month (01-12)": "Monat (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Auf Discord zeigen",
|
||||
"Instant {{action}}": "Sofort {{action}}",
|
||||
"Instant {{action}} Disabled": "Sofort {{action}} deaktiviert",
|
||||
"Annotation": "Anmerkung"
|
||||
"Annotation": "Anmerkung",
|
||||
"Reset Template": "Vorlage zurücksetzen",
|
||||
"Annotation style": "Anmerkungsstil",
|
||||
"Annotation color": "Anmerkungsfarbe",
|
||||
"Annotation time": "Anmerkungszeit",
|
||||
"AI": "KI",
|
||||
"Are you sure you want to re-index this book?": "Möchten Sie dieses Buch wirklich neu indizieren?",
|
||||
"Enable AI in Settings": "KI in den Einstellungen aktivieren",
|
||||
"Index This Book": "Dieses Buch indizieren",
|
||||
"Enable AI search and chat for this book": "KI-Suche und Chat für dieses Buch aktivieren",
|
||||
"Start Indexing": "Indizierung starten",
|
||||
"Indexing book...": "Buch wird indiziert...",
|
||||
"Preparing...": "Vorbereitung...",
|
||||
"Delete this conversation?": "Diese Unterhaltung löschen?",
|
||||
"No conversations yet": "Noch keine Unterhaltungen",
|
||||
"Start a new chat to ask questions about this book": "Starten Sie einen neuen Chat, um Fragen zu diesem Buch zu stellen",
|
||||
"Rename": "Umbenennen",
|
||||
"New Chat": "Neuer Chat",
|
||||
"Chat": "Chat",
|
||||
"Please enter a model ID": "Bitte geben Sie eine Modell-ID ein",
|
||||
"Model not available or invalid": "Modell nicht verfügbar oder ungültig",
|
||||
"Failed to validate model": "Modellvalidierung fehlgeschlagen",
|
||||
"Couldn't connect to Ollama. Is it running?": "Verbindung zu Ollama fehlgeschlagen. Läuft es?",
|
||||
"Invalid API key or connection failed": "Ungültiger API-Schlüssel oder Verbindung fehlgeschlagen",
|
||||
"Connection failed": "Verbindung fehlgeschlagen",
|
||||
"AI Assistant": "KI-Assistent",
|
||||
"Enable AI Assistant": "KI-Assistent aktivieren",
|
||||
"Provider": "Anbieter",
|
||||
"Ollama (Local)": "Ollama (Lokal)",
|
||||
"AI Gateway (Cloud)": "KI-Gateway (Cloud)",
|
||||
"Ollama Configuration": "Ollama-Konfiguration",
|
||||
"Refresh Models": "Modelle aktualisieren",
|
||||
"AI Model": "KI-Modell",
|
||||
"No models detected": "Keine Modelle erkannt",
|
||||
"AI Gateway Configuration": "KI-Gateway-Konfiguration",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Wählen Sie aus einer Auswahl hochwertiger, wirtschaftlicher KI-Modelle. Sie können auch Ihr eigenes Modell verwenden, indem Sie unten \"Benutzerdefiniertes Modell\" auswählen.",
|
||||
"API Key": "API-Schlüssel",
|
||||
"Get Key": "Schlüssel erhalten",
|
||||
"Model": "Modell",
|
||||
"Custom Model...": "Benutzerdefiniertes Modell...",
|
||||
"Custom Model ID": "Benutzerdefinierte Modell-ID",
|
||||
"Validate": "Validieren",
|
||||
"Model available": "Modell verfügbar",
|
||||
"Connection": "Verbindung",
|
||||
"Test Connection": "Verbindung testen",
|
||||
"Connected": "Verbunden"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "Πίνακας σχολιασμών",
|
||||
"Highlighted text": "Επισημασμένο κείμενο",
|
||||
"Annotation note": "Σημείωση σχολιασμού",
|
||||
"Update time": "Ώρα ενημέρωσης",
|
||||
"Date Format Tokens:": "Σύμβολα μορφοποίησης ημερομηνίας:",
|
||||
"Year (4 digits)": "Έτος (4 ψηφία)",
|
||||
"Month (01-12)": "Μήνας (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Εμφάνιση στο Discord",
|
||||
"Instant {{action}}": "Άμεση {{action}}",
|
||||
"Instant {{action}} Disabled": "Άμεση {{action}} απενεργοποιημένη",
|
||||
"Annotation": "Σημείωση"
|
||||
"Annotation": "Σημείωση",
|
||||
"Reset Template": "Επαναφορά προτύπου",
|
||||
"Annotation style": "Στυλ σχολίου",
|
||||
"Annotation color": "Χρώμα σχολίου",
|
||||
"Annotation time": "Ώρα σχολίου",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "Είστε σίγουροι ότι θέλετε να επαναδημιουργήσετε το ευρετήριο αυτού του βιβλίου;",
|
||||
"Enable AI in Settings": "Ενεργοποίηση AI στις ρυθμίσεις",
|
||||
"Index This Book": "Δημιουργία ευρετηρίου για αυτό το βιβλίο",
|
||||
"Enable AI search and chat for this book": "Ενεργοποίηση αναζήτησης AI και συνομιλίας για αυτό το βιβλίο",
|
||||
"Start Indexing": "Έναρξη δημιουργίας ευρετηρίου",
|
||||
"Indexing book...": "Δημιουργία ευρετηρίου βιβλίου...",
|
||||
"Preparing...": "Προετοιμασία...",
|
||||
"Delete this conversation?": "Διαγραφή αυτής της συνομιλίας;",
|
||||
"No conversations yet": "Δεν υπάρχουν συνομιλίες ακόμα",
|
||||
"Start a new chat to ask questions about this book": "Ξεκινήστε μια νέα συνομιλία για να κάνετε ερωτήσεις σχετικά με αυτό το βιβλίο",
|
||||
"Rename": "Μετονομασία",
|
||||
"New Chat": "Νέα συνομιλία",
|
||||
"Chat": "Συνομιλία",
|
||||
"Please enter a model ID": "Εισάγετε ένα αναγνωριστικό μοντέλου",
|
||||
"Model not available or invalid": "Το μοντέλο δεν είναι διαθέσιμο ή δεν είναι έγκυρο",
|
||||
"Failed to validate model": "Αποτυχία επικύρωσης μοντέλου",
|
||||
"Couldn't connect to Ollama. Is it running?": "Δεν ήταν δυνατή η σύνδεση με το Ollama. Εκτελείται;",
|
||||
"Invalid API key or connection failed": "Μη έγκυρο κλειδί API ή αποτυχία σύνδεσης",
|
||||
"Connection failed": "Αποτυχία σύνδεσης",
|
||||
"AI Assistant": "Βοηθός AI",
|
||||
"Enable AI Assistant": "Ενεργοποίηση βοηθού AI",
|
||||
"Provider": "Πάροχος",
|
||||
"Ollama (Local)": "Ollama (Τοπικό)",
|
||||
"AI Gateway (Cloud)": "Πύλη AI (Cloud)",
|
||||
"Ollama Configuration": "Διαμόρφωση Ollama",
|
||||
"Refresh Models": "Ανανέωση μοντέλων",
|
||||
"AI Model": "Μοντέλο AI",
|
||||
"No models detected": "Δεν εντοπίστηκαν μοντέλα",
|
||||
"AI Gateway Configuration": "Διαμόρφωση πύλης AI",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Επιλέξτε από μια συλλογή υψηλής ποιότητας, οικονομικών μοντέλων AI. Μπορείτε επίσης να χρησιμοποιήσετε το δικό σας μοντέλο επιλέγοντας \"Προσαρμοσμένο μοντέλο\" παρακάτω.",
|
||||
"API Key": "Κλειδί API",
|
||||
"Get Key": "Λήψη κλειδιού",
|
||||
"Model": "Μοντέλο",
|
||||
"Custom Model...": "Προσαρμοσμένο μοντέλο...",
|
||||
"Custom Model ID": "Αναγνωριστικό προσαρμοσμένου μοντέλου",
|
||||
"Validate": "Επικύρωση",
|
||||
"Model available": "Το μοντέλο είναι διαθέσιμο",
|
||||
"Connection": "Σύνδεση",
|
||||
"Test Connection": "Δοκιμή σύνδεσης",
|
||||
"Connected": "Συνδεδεμένο"
|
||||
}
|
||||
|
||||
@@ -884,7 +884,6 @@
|
||||
"Array of annotations": "Lista de anotaciones",
|
||||
"Highlighted text": "Texto resaltado",
|
||||
"Annotation note": "Nota de anotación",
|
||||
"Update time": "Hora de actualización",
|
||||
"Date Format Tokens:": "Tokens de formato de fecha:",
|
||||
"Year (4 digits)": "Año (4 dígitos)",
|
||||
"Month (01-12)": "Mes (01-12)",
|
||||
@@ -902,5 +901,50 @@
|
||||
"Show on Discord": "Mostrar en Discord",
|
||||
"Instant {{action}}": "{{action}} instantáneo",
|
||||
"Instant {{action}} Disabled": "{{action}} instantáneo desactivado",
|
||||
"Annotation": "Anotación"
|
||||
"Annotation": "Anotación",
|
||||
"Reset Template": "Restablecer plantilla",
|
||||
"Annotation style": "Estilo de anotación",
|
||||
"Annotation color": "Color de anotación",
|
||||
"Annotation time": "Hora de anotación",
|
||||
"AI": "IA",
|
||||
"Are you sure you want to re-index this book?": "¿Está seguro de que desea reindexar este libro?",
|
||||
"Enable AI in Settings": "Habilitar IA en Configuración",
|
||||
"Index This Book": "Indexar este libro",
|
||||
"Enable AI search and chat for this book": "Habilitar búsqueda y chat con IA para este libro",
|
||||
"Start Indexing": "Iniciar indexación",
|
||||
"Indexing book...": "Indexando libro...",
|
||||
"Preparing...": "Preparando...",
|
||||
"Delete this conversation?": "¿Eliminar esta conversación?",
|
||||
"No conversations yet": "Aún no hay conversaciones",
|
||||
"Start a new chat to ask questions about this book": "Inicie un nuevo chat para hacer preguntas sobre este libro",
|
||||
"Rename": "Renombrar",
|
||||
"New Chat": "Nuevo chat",
|
||||
"Chat": "Chat",
|
||||
"Please enter a model ID": "Por favor, ingrese un ID de modelo",
|
||||
"Model not available or invalid": "Modelo no disponible o inválido",
|
||||
"Failed to validate model": "Error al validar el modelo",
|
||||
"Couldn't connect to Ollama. Is it running?": "No se pudo conectar a Ollama. ¿Está ejecutándose?",
|
||||
"Invalid API key or connection failed": "Clave API inválida o conexión fallida",
|
||||
"Connection failed": "Conexión fallida",
|
||||
"AI Assistant": "Asistente de IA",
|
||||
"Enable AI Assistant": "Habilitar asistente de IA",
|
||||
"Provider": "Proveedor",
|
||||
"Ollama (Local)": "Ollama (Local)",
|
||||
"AI Gateway (Cloud)": "Pasarela de IA (Nube)",
|
||||
"Ollama Configuration": "Configuración de Ollama",
|
||||
"Refresh Models": "Actualizar modelos",
|
||||
"AI Model": "Modelo de IA",
|
||||
"No models detected": "No se detectaron modelos",
|
||||
"AI Gateway Configuration": "Configuración de pasarela de IA",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Elija entre una selección de modelos de IA de alta calidad y económicos. También puede usar su propio modelo seleccionando \"Modelo personalizado\" a continuación.",
|
||||
"API Key": "Clave API",
|
||||
"Get Key": "Obtener clave",
|
||||
"Model": "Modelo",
|
||||
"Custom Model...": "Modelo personalizado...",
|
||||
"Custom Model ID": "ID de modelo personalizado",
|
||||
"Validate": "Validar",
|
||||
"Model available": "Modelo disponible",
|
||||
"Connection": "Conexión",
|
||||
"Test Connection": "Probar conexión",
|
||||
"Connected": "Conectado"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "آرایه یادداشتها",
|
||||
"Highlighted text": "متن برجستهشده",
|
||||
"Annotation note": "یادداشت حاشیه",
|
||||
"Update time": "زمان بهروزرسانی",
|
||||
"Date Format Tokens:": "نشانههای قالب تاریخ:",
|
||||
"Year (4 digits)": "سال (۴ رقم)",
|
||||
"Month (01-12)": "ماه (۰۱-۱۲)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "نمایش در Discord",
|
||||
"Instant {{action}}": "{{action}} فوری",
|
||||
"Instant {{action}} Disabled": "{{action}} فوری غیرفعال شد",
|
||||
"Annotation": "یادداشت"
|
||||
"Annotation": "یادداشت",
|
||||
"Reset Template": "بازنشانی قالب",
|
||||
"Annotation style": "سبک یادداشت",
|
||||
"Annotation color": "رنگ یادداشت",
|
||||
"Annotation time": "زمان یادداشت",
|
||||
"AI": "هوش مصنوعی",
|
||||
"Are you sure you want to re-index this book?": "آیا مطمئن هستید که میخواهید این کتاب را دوباره فهرست کنید؟",
|
||||
"Enable AI in Settings": "فعال کردن هوش مصنوعی در تنظیمات",
|
||||
"Index This Book": "فهرست کردن این کتاب",
|
||||
"Enable AI search and chat for this book": "فعال کردن جستجو و گفتگوی هوش مصنوعی برای این کتاب",
|
||||
"Start Indexing": "شروع فهرستبندی",
|
||||
"Indexing book...": "در حال فهرستبندی کتاب...",
|
||||
"Preparing...": "در حال آمادهسازی...",
|
||||
"Delete this conversation?": "این مکالمه حذف شود؟",
|
||||
"No conversations yet": "هنوز مکالمهای وجود ندارد",
|
||||
"Start a new chat to ask questions about this book": "یک گفتگوی جدید برای پرسیدن سؤال درباره این کتاب شروع کنید",
|
||||
"Rename": "تغییر نام",
|
||||
"New Chat": "گفتگوی جدید",
|
||||
"Chat": "گفتگو",
|
||||
"Please enter a model ID": "لطفاً شناسه مدل را وارد کنید",
|
||||
"Model not available or invalid": "مدل در دسترس نیست یا نامعتبر است",
|
||||
"Failed to validate model": "اعتبارسنجی مدل ناموفق بود",
|
||||
"Couldn't connect to Ollama. Is it running?": "اتصال به Ollama ممکن نشد. آیا در حال اجرا است؟",
|
||||
"Invalid API key or connection failed": "کلید API نامعتبر است یا اتصال ناموفق بود",
|
||||
"Connection failed": "اتصال ناموفق بود",
|
||||
"AI Assistant": "دستیار هوش مصنوعی",
|
||||
"Enable AI Assistant": "فعال کردن دستیار هوش مصنوعی",
|
||||
"Provider": "ارائهدهنده",
|
||||
"Ollama (Local)": "Ollama (محلی)",
|
||||
"AI Gateway (Cloud)": "دروازه هوش مصنوعی (ابری)",
|
||||
"Ollama Configuration": "پیکربندی Ollama",
|
||||
"Refresh Models": "بازخوانی مدلها",
|
||||
"AI Model": "مدل هوش مصنوعی",
|
||||
"No models detected": "هیچ مدلی شناسایی نشد",
|
||||
"AI Gateway Configuration": "پیکربندی دروازه هوش مصنوعی",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "از میان مجموعهای از مدلهای هوش مصنوعی با کیفیت و اقتصادی انتخاب کنید. همچنین میتوانید با انتخاب \"مدل سفارشی\" در زیر، مدل خود را استفاده کنید.",
|
||||
"API Key": "کلید API",
|
||||
"Get Key": "دریافت کلید",
|
||||
"Model": "مدل",
|
||||
"Custom Model...": "مدل سفارشی...",
|
||||
"Custom Model ID": "شناسه مدل سفارشی",
|
||||
"Validate": "اعتبارسنجی",
|
||||
"Model available": "مدل در دسترس است",
|
||||
"Connection": "اتصال",
|
||||
"Test Connection": "تست اتصال",
|
||||
"Connected": "متصل"
|
||||
}
|
||||
|
||||
@@ -884,7 +884,6 @@
|
||||
"Array of annotations": "Liste d'annotations",
|
||||
"Highlighted text": "Texte surligné",
|
||||
"Annotation note": "Note d'annotation",
|
||||
"Update time": "Heure de mise à jour",
|
||||
"Date Format Tokens:": "Jetons de format de date :",
|
||||
"Year (4 digits)": "Année (4 chiffres)",
|
||||
"Month (01-12)": "Mois (01-12)",
|
||||
@@ -902,5 +901,50 @@
|
||||
"Show on Discord": "Afficher sur Discord",
|
||||
"Instant {{action}}": "{{action}} instantané",
|
||||
"Instant {{action}} Disabled": "{{action}} instantané désactivé",
|
||||
"Annotation": "Annotation"
|
||||
"Annotation": "Annotation",
|
||||
"Reset Template": "Réinitialiser le modèle",
|
||||
"Annotation style": "Style d'annotation",
|
||||
"Annotation color": "Couleur d'annotation",
|
||||
"Annotation time": "Heure d'annotation",
|
||||
"AI": "IA",
|
||||
"Are you sure you want to re-index this book?": "Voulez-vous vraiment réindexer ce livre ?",
|
||||
"Enable AI in Settings": "Activer l'IA dans les paramètres",
|
||||
"Index This Book": "Indexer ce livre",
|
||||
"Enable AI search and chat for this book": "Activer la recherche IA et le chat pour ce livre",
|
||||
"Start Indexing": "Démarrer l'indexation",
|
||||
"Indexing book...": "Indexation du livre...",
|
||||
"Preparing...": "Préparation...",
|
||||
"Delete this conversation?": "Supprimer cette conversation ?",
|
||||
"No conversations yet": "Pas encore de conversations",
|
||||
"Start a new chat to ask questions about this book": "Démarrez une nouvelle conversation pour poser des questions sur ce livre",
|
||||
"Rename": "Renommer",
|
||||
"New Chat": "Nouvelle conversation",
|
||||
"Chat": "Chat",
|
||||
"Please enter a model ID": "Veuillez entrer un ID de modèle",
|
||||
"Model not available or invalid": "Modèle non disponible ou invalide",
|
||||
"Failed to validate model": "Échec de la validation du modèle",
|
||||
"Couldn't connect to Ollama. Is it running?": "Impossible de se connecter à Ollama. Est-il en cours d'exécution ?",
|
||||
"Invalid API key or connection failed": "Clé API invalide ou échec de connexion",
|
||||
"Connection failed": "Échec de connexion",
|
||||
"AI Assistant": "Assistant IA",
|
||||
"Enable AI Assistant": "Activer l'assistant IA",
|
||||
"Provider": "Fournisseur",
|
||||
"Ollama (Local)": "Ollama (Local)",
|
||||
"AI Gateway (Cloud)": "Passerelle IA (Cloud)",
|
||||
"Ollama Configuration": "Configuration Ollama",
|
||||
"Refresh Models": "Actualiser les modèles",
|
||||
"AI Model": "Modèle IA",
|
||||
"No models detected": "Aucun modèle détecté",
|
||||
"AI Gateway Configuration": "Configuration de la passerelle IA",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Choisissez parmi une sélection de modèles IA de haute qualité et économiques. Vous pouvez également utiliser votre propre modèle en sélectionnant \"Modèle personnalisé\" ci-dessous.",
|
||||
"API Key": "Clé API",
|
||||
"Get Key": "Obtenir la clé",
|
||||
"Model": "Modèle",
|
||||
"Custom Model...": "Modèle personnalisé...",
|
||||
"Custom Model ID": "ID du modèle personnalisé",
|
||||
"Validate": "Valider",
|
||||
"Model available": "Modèle disponible",
|
||||
"Connection": "Connexion",
|
||||
"Test Connection": "Tester la connexion",
|
||||
"Connected": "Connecté"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "एनोटेशन की सूची",
|
||||
"Highlighted text": "हाइलाइट किया गया पाठ",
|
||||
"Annotation note": "एनोटेशन नोट",
|
||||
"Update time": "अपडेट समय",
|
||||
"Date Format Tokens:": "तिथि प्रारूप टोकन:",
|
||||
"Year (4 digits)": "वर्ष (4 अंक)",
|
||||
"Month (01-12)": "माह (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Discord पर दिखाएं",
|
||||
"Instant {{action}}": "तत्काल {{action}}",
|
||||
"Instant {{action}} Disabled": "तत्काल {{action}} अक्षम",
|
||||
"Annotation": "टिप्पणी"
|
||||
"Annotation": "टिप्पणी",
|
||||
"Reset Template": "टेम्पलेट रीसेट करें",
|
||||
"Annotation style": "एनोटेशन शैली",
|
||||
"Annotation color": "एनोटेशन रंग",
|
||||
"Annotation time": "एनोटेशन समय",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "क्या आप वाकई इस पुस्तक को फिर से इंडेक्स करना चाहते हैं?",
|
||||
"Enable AI in Settings": "सेटिंग्स में AI सक्षम करें",
|
||||
"Index This Book": "इस पुस्तक को इंडेक्स करें",
|
||||
"Enable AI search and chat for this book": "इस पुस्तक के लिए AI खोज और चैट सक्षम करें",
|
||||
"Start Indexing": "इंडेक्सिंग शुरू करें",
|
||||
"Indexing book...": "पुस्तक इंडेक्स हो रही है...",
|
||||
"Preparing...": "तैयारी हो रही है...",
|
||||
"Delete this conversation?": "इस वार्तालाप को हटाएं?",
|
||||
"No conversations yet": "अभी तक कोई वार्तालाप नहीं",
|
||||
"Start a new chat to ask questions about this book": "इस पुस्तक के बारे में प्रश्न पूछने के लिए नई चैट शुरू करें",
|
||||
"Rename": "नाम बदलें",
|
||||
"New Chat": "नई चैट",
|
||||
"Chat": "चैट",
|
||||
"Please enter a model ID": "कृपया मॉडल ID दर्ज करें",
|
||||
"Model not available or invalid": "मॉडल उपलब्ध नहीं या अमान्य है",
|
||||
"Failed to validate model": "मॉडल सत्यापित करने में विफल",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollama से कनेक्ट नहीं हो सका। क्या यह चल रहा है?",
|
||||
"Invalid API key or connection failed": "अमान्य API कुंजी या कनेक्शन विफल",
|
||||
"Connection failed": "कनेक्शन विफल",
|
||||
"AI Assistant": "AI सहायक",
|
||||
"Enable AI Assistant": "AI सहायक सक्षम करें",
|
||||
"Provider": "प्रदाता",
|
||||
"Ollama (Local)": "Ollama (स्थानीय)",
|
||||
"AI Gateway (Cloud)": "AI गेटवे (क्लाउड)",
|
||||
"Ollama Configuration": "Ollama कॉन्फ़िगरेशन",
|
||||
"Refresh Models": "मॉडल रीफ्रेश करें",
|
||||
"AI Model": "AI मॉडल",
|
||||
"No models detected": "कोई मॉडल नहीं मिला",
|
||||
"AI Gateway Configuration": "AI गेटवे कॉन्फ़िगरेशन",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "उच्च-गुणवत्ता, किफायती AI मॉडल के चयन में से चुनें। आप नीचे \"कस्टम मॉडल\" का चयन करके अपना मॉडल भी उपयोग कर सकते हैं।",
|
||||
"API Key": "API कुंजी",
|
||||
"Get Key": "कुंजी प्राप्त करें",
|
||||
"Model": "मॉडल",
|
||||
"Custom Model...": "कस्टम मॉडल...",
|
||||
"Custom Model ID": "कस्टम मॉडल ID",
|
||||
"Validate": "सत्यापित करें",
|
||||
"Model available": "मॉडल उपलब्ध",
|
||||
"Connection": "कनेक्शन",
|
||||
"Test Connection": "कनेक्शन परीक्षण",
|
||||
"Connected": "कनेक्टेड"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "Daftar anotasi",
|
||||
"Highlighted text": "Teks yang disorot",
|
||||
"Annotation note": "Catatan anotasi",
|
||||
"Update time": "Waktu pembaruan",
|
||||
"Date Format Tokens:": "Token Format Tanggal:",
|
||||
"Year (4 digits)": "Tahun (4 digit)",
|
||||
"Month (01-12)": "Bulan (01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "Tampilkan di Discord",
|
||||
"Instant {{action}}": "{{action}} Instan",
|
||||
"Instant {{action}} Disabled": "{{action}} Instan Dinonaktifkan",
|
||||
"Annotation": "Anotasi"
|
||||
"Annotation": "Anotasi",
|
||||
"Reset Template": "Atur Ulang Template",
|
||||
"Annotation style": "Gaya anotasi",
|
||||
"Annotation color": "Warna anotasi",
|
||||
"Annotation time": "Waktu anotasi",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "Apakah Anda yakin ingin mengindeks ulang buku ini?",
|
||||
"Enable AI in Settings": "Aktifkan AI di Pengaturan",
|
||||
"Index This Book": "Indeks Buku Ini",
|
||||
"Enable AI search and chat for this book": "Aktifkan pencarian AI dan obrolan untuk buku ini",
|
||||
"Start Indexing": "Mulai Mengindeks",
|
||||
"Indexing book...": "Mengindeks buku...",
|
||||
"Preparing...": "Mempersiapkan...",
|
||||
"Delete this conversation?": "Hapus percakapan ini?",
|
||||
"No conversations yet": "Belum ada percakapan",
|
||||
"Start a new chat to ask questions about this book": "Mulai obrolan baru untuk mengajukan pertanyaan tentang buku ini",
|
||||
"Rename": "Ubah nama",
|
||||
"New Chat": "Obrolan Baru",
|
||||
"Chat": "Obrolan",
|
||||
"Please enter a model ID": "Silakan masukkan ID model",
|
||||
"Model not available or invalid": "Model tidak tersedia atau tidak valid",
|
||||
"Failed to validate model": "Gagal memvalidasi model",
|
||||
"Couldn't connect to Ollama. Is it running?": "Tidak dapat terhubung ke Ollama. Apakah sedang berjalan?",
|
||||
"Invalid API key or connection failed": "Kunci API tidak valid atau koneksi gagal",
|
||||
"Connection failed": "Koneksi gagal",
|
||||
"AI Assistant": "Asisten AI",
|
||||
"Enable AI Assistant": "Aktifkan Asisten AI",
|
||||
"Provider": "Penyedia",
|
||||
"Ollama (Local)": "Ollama (Lokal)",
|
||||
"AI Gateway (Cloud)": "Gateway AI (Cloud)",
|
||||
"Ollama Configuration": "Konfigurasi Ollama",
|
||||
"Refresh Models": "Segarkan Model",
|
||||
"AI Model": "Model AI",
|
||||
"No models detected": "Tidak ada model terdeteksi",
|
||||
"AI Gateway Configuration": "Konfigurasi Gateway AI",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Pilih dari pilihan model AI berkualitas tinggi dan ekonomis. Anda juga dapat menggunakan model Anda sendiri dengan memilih \"Model Kustom\" di bawah.",
|
||||
"API Key": "Kunci API",
|
||||
"Get Key": "Dapatkan Kunci",
|
||||
"Model": "Model",
|
||||
"Custom Model...": "Model Kustom...",
|
||||
"Custom Model ID": "ID Model Kustom",
|
||||
"Validate": "Validasi",
|
||||
"Model available": "Model tersedia",
|
||||
"Connection": "Koneksi",
|
||||
"Test Connection": "Uji Koneksi",
|
||||
"Connected": "Terhubung"
|
||||
}
|
||||
|
||||
@@ -884,7 +884,6 @@
|
||||
"Array of annotations": "Elenco annotazioni",
|
||||
"Highlighted text": "Testo evidenziato",
|
||||
"Annotation note": "Nota annotazione",
|
||||
"Update time": "Ora aggiornamento",
|
||||
"Date Format Tokens:": "Token formato data:",
|
||||
"Year (4 digits)": "Anno (4 cifre)",
|
||||
"Month (01-12)": "Mese (01-12)",
|
||||
@@ -902,5 +901,50 @@
|
||||
"Show on Discord": "Mostra su Discord",
|
||||
"Instant {{action}}": "{{action}} istantaneo",
|
||||
"Instant {{action}} Disabled": "{{action}} istantaneo disattivato",
|
||||
"Annotation": "Annotazione"
|
||||
"Annotation": "Annotazione",
|
||||
"Reset Template": "Reimposta modello",
|
||||
"Annotation style": "Stile annotazione",
|
||||
"Annotation color": "Colore annotazione",
|
||||
"Annotation time": "Ora annotazione",
|
||||
"AI": "IA",
|
||||
"Are you sure you want to re-index this book?": "Sei sicuro di voler reindicizzare questo libro?",
|
||||
"Enable AI in Settings": "Abilita IA nelle impostazioni",
|
||||
"Index This Book": "Indicizza questo libro",
|
||||
"Enable AI search and chat for this book": "Abilita ricerca IA e chat per questo libro",
|
||||
"Start Indexing": "Avvia indicizzazione",
|
||||
"Indexing book...": "Indicizzazione libro...",
|
||||
"Preparing...": "Preparazione...",
|
||||
"Delete this conversation?": "Eliminare questa conversazione?",
|
||||
"No conversations yet": "Ancora nessuna conversazione",
|
||||
"Start a new chat to ask questions about this book": "Avvia una nuova chat per fare domande su questo libro",
|
||||
"Rename": "Rinomina",
|
||||
"New Chat": "Nuova chat",
|
||||
"Chat": "Chat",
|
||||
"Please enter a model ID": "Inserisci un ID modello",
|
||||
"Model not available or invalid": "Modello non disponibile o non valido",
|
||||
"Failed to validate model": "Validazione modello fallita",
|
||||
"Couldn't connect to Ollama. Is it running?": "Impossibile connettersi a Ollama. È in esecuzione?",
|
||||
"Invalid API key or connection failed": "Chiave API non valida o connessione fallita",
|
||||
"Connection failed": "Connessione fallita",
|
||||
"AI Assistant": "Assistente IA",
|
||||
"Enable AI Assistant": "Abilita assistente IA",
|
||||
"Provider": "Fornitore",
|
||||
"Ollama (Local)": "Ollama (Locale)",
|
||||
"AI Gateway (Cloud)": "Gateway IA (Cloud)",
|
||||
"Ollama Configuration": "Configurazione Ollama",
|
||||
"Refresh Models": "Aggiorna modelli",
|
||||
"AI Model": "Modello IA",
|
||||
"No models detected": "Nessun modello rilevato",
|
||||
"AI Gateway Configuration": "Configurazione gateway IA",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Scegli tra una selezione di modelli IA di alta qualità ed economici. Puoi anche usare il tuo modello selezionando \"Modello personalizzato\" qui sotto.",
|
||||
"API Key": "Chiave API",
|
||||
"Get Key": "Ottieni chiave",
|
||||
"Model": "Modello",
|
||||
"Custom Model...": "Modello personalizzato...",
|
||||
"Custom Model ID": "ID modello personalizzato",
|
||||
"Validate": "Convalida",
|
||||
"Model available": "Modello disponibile",
|
||||
"Connection": "Connessione",
|
||||
"Test Connection": "Testa connessione",
|
||||
"Connected": "Connesso"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "注釈の配列",
|
||||
"Highlighted text": "ハイライトテキスト",
|
||||
"Annotation note": "注釈ノート",
|
||||
"Update time": "更新時刻",
|
||||
"Date Format Tokens:": "日付形式トークン:",
|
||||
"Year (4 digits)": "年(4桁)",
|
||||
"Month (01-12)": "月(01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "Discordに表示",
|
||||
"Instant {{action}}": "インスタント{{action}}",
|
||||
"Instant {{action}} Disabled": "インスタント{{action}}を無効化",
|
||||
"Annotation": "注釈"
|
||||
"Annotation": "注釈",
|
||||
"Reset Template": "テンプレートをリセット",
|
||||
"Annotation style": "注釈スタイル",
|
||||
"Annotation color": "注釈の色",
|
||||
"Annotation time": "注釈時間",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "この本を再インデックスしてもよろしいですか?",
|
||||
"Enable AI in Settings": "設定でAIを有効にする",
|
||||
"Index This Book": "この本をインデックス",
|
||||
"Enable AI search and chat for this book": "この本のAI検索とチャットを有効にする",
|
||||
"Start Indexing": "インデックス開始",
|
||||
"Indexing book...": "本をインデックス中...",
|
||||
"Preparing...": "準備中...",
|
||||
"Delete this conversation?": "この会話を削除しますか?",
|
||||
"No conversations yet": "まだ会話がありません",
|
||||
"Start a new chat to ask questions about this book": "この本について質問するには新しいチャットを開始してください",
|
||||
"Rename": "名前を変更",
|
||||
"New Chat": "新しいチャット",
|
||||
"Chat": "チャット",
|
||||
"Please enter a model ID": "モデルIDを入力してください",
|
||||
"Model not available or invalid": "モデルが利用できないか無効です",
|
||||
"Failed to validate model": "モデルの検証に失敗しました",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollamaに接続できませんでした。実行中ですか?",
|
||||
"Invalid API key or connection failed": "APIキーが無効か接続に失敗しました",
|
||||
"Connection failed": "接続に失敗しました",
|
||||
"AI Assistant": "AIアシスタント",
|
||||
"Enable AI Assistant": "AIアシスタントを有効にする",
|
||||
"Provider": "プロバイダー",
|
||||
"Ollama (Local)": "Ollama(ローカル)",
|
||||
"AI Gateway (Cloud)": "AIゲートウェイ(クラウド)",
|
||||
"Ollama Configuration": "Ollama設定",
|
||||
"Refresh Models": "モデルを更新",
|
||||
"AI Model": "AIモデル",
|
||||
"No models detected": "モデルが検出されませんでした",
|
||||
"AI Gateway Configuration": "AIゲートウェイ設定",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "高品質で経済的なAIモデルからお選びください。下の「カスタムモデル」を選択して独自のモデルを使用することもできます。",
|
||||
"API Key": "APIキー",
|
||||
"Get Key": "キーを取得",
|
||||
"Model": "モデル",
|
||||
"Custom Model...": "カスタムモデル...",
|
||||
"Custom Model ID": "カスタムモデルID",
|
||||
"Validate": "検証",
|
||||
"Model available": "モデルが利用可能",
|
||||
"Connection": "接続",
|
||||
"Test Connection": "接続をテスト",
|
||||
"Connected": "接続済み"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "주석 배열",
|
||||
"Highlighted text": "하이라이트된 텍스트",
|
||||
"Annotation note": "주석 노트",
|
||||
"Update time": "업데이트 시간",
|
||||
"Date Format Tokens:": "날짜 형식 토큰:",
|
||||
"Year (4 digits)": "연도 (4자리)",
|
||||
"Month (01-12)": "월 (01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "Discord에 표시",
|
||||
"Instant {{action}}": "즉시 {{action}}",
|
||||
"Instant {{action}} Disabled": "즉시 {{action}} 비활성화",
|
||||
"Annotation": "주석"
|
||||
"Annotation": "주석",
|
||||
"Reset Template": "템플릿 초기화",
|
||||
"Annotation style": "주석 스타일",
|
||||
"Annotation color": "주석 색상",
|
||||
"Annotation time": "주석 시간",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "이 책을 다시 인덱싱하시겠습니까?",
|
||||
"Enable AI in Settings": "설정에서 AI 활성화",
|
||||
"Index This Book": "이 책 인덱싱",
|
||||
"Enable AI search and chat for this book": "이 책에 대한 AI 검색 및 채팅 활성화",
|
||||
"Start Indexing": "인덱싱 시작",
|
||||
"Indexing book...": "책 인덱싱 중...",
|
||||
"Preparing...": "준비 중...",
|
||||
"Delete this conversation?": "이 대화를 삭제하시겠습니까?",
|
||||
"No conversations yet": "아직 대화가 없습니다",
|
||||
"Start a new chat to ask questions about this book": "이 책에 대해 질문하려면 새 채팅을 시작하세요",
|
||||
"Rename": "이름 변경",
|
||||
"New Chat": "새 채팅",
|
||||
"Chat": "채팅",
|
||||
"Please enter a model ID": "모델 ID를 입력하세요",
|
||||
"Model not available or invalid": "모델을 사용할 수 없거나 유효하지 않습니다",
|
||||
"Failed to validate model": "모델 검증 실패",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollama에 연결할 수 없습니다. 실행 중인가요?",
|
||||
"Invalid API key or connection failed": "API 키가 유효하지 않거나 연결 실패",
|
||||
"Connection failed": "연결 실패",
|
||||
"AI Assistant": "AI 어시스턴트",
|
||||
"Enable AI Assistant": "AI 어시스턴트 활성화",
|
||||
"Provider": "제공자",
|
||||
"Ollama (Local)": "Ollama (로컬)",
|
||||
"AI Gateway (Cloud)": "AI 게이트웨이 (클라우드)",
|
||||
"Ollama Configuration": "Ollama 설정",
|
||||
"Refresh Models": "모델 새로고침",
|
||||
"AI Model": "AI 모델",
|
||||
"No models detected": "모델이 감지되지 않았습니다",
|
||||
"AI Gateway Configuration": "AI 게이트웨이 설정",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "고품질의 경제적인 AI 모델 중에서 선택하세요. 아래의 \"사용자 정의 모델\"을 선택하여 자신의 모델을 사용할 수도 있습니다.",
|
||||
"API Key": "API 키",
|
||||
"Get Key": "키 받기",
|
||||
"Model": "모델",
|
||||
"Custom Model...": "사용자 정의 모델...",
|
||||
"Custom Model ID": "사용자 정의 모델 ID",
|
||||
"Validate": "검증",
|
||||
"Model available": "모델 사용 가능",
|
||||
"Connection": "연결",
|
||||
"Test Connection": "연결 테스트",
|
||||
"Connected": "연결됨"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "Senarai anotasi",
|
||||
"Highlighted text": "Teks yang diserlahkan",
|
||||
"Annotation note": "Nota anotasi",
|
||||
"Update time": "Masa kemas kini",
|
||||
"Date Format Tokens:": "Token Format Tarikh:",
|
||||
"Year (4 digits)": "Tahun (4 digit)",
|
||||
"Month (01-12)": "Bulan (01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "Papar di Discord",
|
||||
"Instant {{action}}": "{{action}} Segera",
|
||||
"Instant {{action}} Disabled": "{{action}} Segera Dilumpuhkan",
|
||||
"Annotation": "Anotasi"
|
||||
"Annotation": "Anotasi",
|
||||
"Reset Template": "Tetapkan Semula Templat",
|
||||
"Annotation style": "Gaya anotasi",
|
||||
"Annotation color": "Warna anotasi",
|
||||
"Annotation time": "Masa anotasi",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "Adakah anda pasti mahu mengindeks semula buku ini?",
|
||||
"Enable AI in Settings": "Aktifkan AI dalam Tetapan",
|
||||
"Index This Book": "Indeks Buku Ini",
|
||||
"Enable AI search and chat for this book": "Aktifkan carian AI dan sembang untuk buku ini",
|
||||
"Start Indexing": "Mula Mengindeks",
|
||||
"Indexing book...": "Mengindeks buku...",
|
||||
"Preparing...": "Menyediakan...",
|
||||
"Delete this conversation?": "Padam perbualan ini?",
|
||||
"No conversations yet": "Tiada perbualan lagi",
|
||||
"Start a new chat to ask questions about this book": "Mulakan sembang baharu untuk bertanya tentang buku ini",
|
||||
"Rename": "Namakan Semula",
|
||||
"New Chat": "Sembang Baharu",
|
||||
"Chat": "Sembang",
|
||||
"Please enter a model ID": "Sila masukkan ID model",
|
||||
"Model not available or invalid": "Model tidak tersedia atau tidak sah",
|
||||
"Failed to validate model": "Gagal mengesahkan model",
|
||||
"Couldn't connect to Ollama. Is it running?": "Tidak dapat menyambung ke Ollama. Adakah ia sedang berjalan?",
|
||||
"Invalid API key or connection failed": "Kunci API tidak sah atau sambungan gagal",
|
||||
"Connection failed": "Sambungan gagal",
|
||||
"AI Assistant": "Pembantu AI",
|
||||
"Enable AI Assistant": "Aktifkan Pembantu AI",
|
||||
"Provider": "Pembekal",
|
||||
"Ollama (Local)": "Ollama (Tempatan)",
|
||||
"AI Gateway (Cloud)": "Gateway AI (Awan)",
|
||||
"Ollama Configuration": "Konfigurasi Ollama",
|
||||
"Refresh Models": "Muat Semula Model",
|
||||
"AI Model": "Model AI",
|
||||
"No models detected": "Tiada model dikesan",
|
||||
"AI Gateway Configuration": "Konfigurasi Gateway AI",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Pilih dari pelbagai model AI berkualiti tinggi dan ekonomi. Anda juga boleh menggunakan model anda sendiri dengan memilih \"Model Tersuai\" di bawah.",
|
||||
"API Key": "Kunci API",
|
||||
"Get Key": "Dapatkan Kunci",
|
||||
"Model": "Model",
|
||||
"Custom Model...": "Model Tersuai...",
|
||||
"Custom Model ID": "ID Model Tersuai",
|
||||
"Validate": "Sahkan",
|
||||
"Model available": "Model tersedia",
|
||||
"Connection": "Sambungan",
|
||||
"Test Connection": "Uji Sambungan",
|
||||
"Connected": "Disambung"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "Reeks annotaties",
|
||||
"Highlighted text": "Gemarkeerde tekst",
|
||||
"Annotation note": "Annotatienotitie",
|
||||
"Update time": "Updatetijd",
|
||||
"Date Format Tokens:": "Datumformaattokens:",
|
||||
"Year (4 digits)": "Jaar (4 cijfers)",
|
||||
"Month (01-12)": "Maand (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Toon op Discord",
|
||||
"Instant {{action}}": "Directe {{action}}",
|
||||
"Instant {{action}} Disabled": "Directe {{action}} uitgeschakeld",
|
||||
"Annotation": "Annotatie"
|
||||
"Annotation": "Annotatie",
|
||||
"Reset Template": "Sjabloon resetten",
|
||||
"Annotation style": "Annotatiestijl",
|
||||
"Annotation color": "Annotatiekleur",
|
||||
"Annotation time": "Annotatietijd",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "Weet u zeker dat u dit boek opnieuw wilt indexeren?",
|
||||
"Enable AI in Settings": "AI inschakelen in Instellingen",
|
||||
"Index This Book": "Dit boek indexeren",
|
||||
"Enable AI search and chat for this book": "AI-zoeken en chat voor dit boek inschakelen",
|
||||
"Start Indexing": "Indexeren starten",
|
||||
"Indexing book...": "Boek wordt geïndexeerd...",
|
||||
"Preparing...": "Voorbereiden...",
|
||||
"Delete this conversation?": "Dit gesprek verwijderen?",
|
||||
"No conversations yet": "Nog geen gesprekken",
|
||||
"Start a new chat to ask questions about this book": "Start een nieuwe chat om vragen te stellen over dit boek",
|
||||
"Rename": "Hernoemen",
|
||||
"New Chat": "Nieuwe chat",
|
||||
"Chat": "Chat",
|
||||
"Please enter a model ID": "Voer een model-ID in",
|
||||
"Model not available or invalid": "Model niet beschikbaar of ongeldig",
|
||||
"Failed to validate model": "Model valideren mislukt",
|
||||
"Couldn't connect to Ollama. Is it running?": "Kon geen verbinding maken met Ollama. Is het actief?",
|
||||
"Invalid API key or connection failed": "Ongeldige API-sleutel of verbinding mislukt",
|
||||
"Connection failed": "Verbinding mislukt",
|
||||
"AI Assistant": "AI-assistent",
|
||||
"Enable AI Assistant": "AI-assistent inschakelen",
|
||||
"Provider": "Provider",
|
||||
"Ollama (Local)": "Ollama (Lokaal)",
|
||||
"AI Gateway (Cloud)": "AI-gateway (Cloud)",
|
||||
"Ollama Configuration": "Ollama-configuratie",
|
||||
"Refresh Models": "Modellen vernieuwen",
|
||||
"AI Model": "AI-model",
|
||||
"No models detected": "Geen modellen gedetecteerd",
|
||||
"AI Gateway Configuration": "AI-gateway configuratie",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Kies uit een selectie van hoogwaardige, voordelige AI-modellen. U kunt ook uw eigen model gebruiken door hieronder \"Aangepast model\" te selecteren.",
|
||||
"API Key": "API-sleutel",
|
||||
"Get Key": "Sleutel ophalen",
|
||||
"Model": "Model",
|
||||
"Custom Model...": "Aangepast model...",
|
||||
"Custom Model ID": "Aangepast model-ID",
|
||||
"Validate": "Valideren",
|
||||
"Model available": "Model beschikbaar",
|
||||
"Connection": "Verbinding",
|
||||
"Test Connection": "Verbinding testen",
|
||||
"Connected": "Verbonden"
|
||||
}
|
||||
|
||||
@@ -894,7 +894,6 @@
|
||||
"Array of annotations": "Tablica adnotacji",
|
||||
"Highlighted text": "Zaznaczony tekst",
|
||||
"Annotation note": "Notatka adnotacji",
|
||||
"Update time": "Czas aktualizacji",
|
||||
"Date Format Tokens:": "Tokeny formatu daty:",
|
||||
"Year (4 digits)": "Rok (4 cyfry)",
|
||||
"Month (01-12)": "Miesiąc (01-12)",
|
||||
@@ -912,5 +911,50 @@
|
||||
"Show on Discord": "Pokaż na Discord",
|
||||
"Instant {{action}}": "Natychmiastowe {{action}}",
|
||||
"Instant {{action}} Disabled": "Natychmiastowe {{action}} wyłączone",
|
||||
"Annotation": "Adnotacja"
|
||||
"Annotation": "Adnotacja",
|
||||
"Reset Template": "Resetuj szablon",
|
||||
"Annotation style": "Styl adnotacji",
|
||||
"Annotation color": "Kolor adnotacji",
|
||||
"Annotation time": "Czas adnotacji",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "Czy na pewno chcesz ponownie zaindeksować tę książkę?",
|
||||
"Enable AI in Settings": "Włącz AI w ustawieniach",
|
||||
"Index This Book": "Zaindeksuj tę książkę",
|
||||
"Enable AI search and chat for this book": "Włącz wyszukiwanie AI i czat dla tej książki",
|
||||
"Start Indexing": "Rozpocznij indeksowanie",
|
||||
"Indexing book...": "Indeksowanie książki...",
|
||||
"Preparing...": "Przygotowywanie...",
|
||||
"Delete this conversation?": "Usunąć tę rozmowę?",
|
||||
"No conversations yet": "Brak rozmów",
|
||||
"Start a new chat to ask questions about this book": "Rozpocznij nowy czat, aby zadać pytania o tę książkę",
|
||||
"Rename": "Zmień nazwę",
|
||||
"New Chat": "Nowy czat",
|
||||
"Chat": "Czat",
|
||||
"Please enter a model ID": "Wprowadź ID modelu",
|
||||
"Model not available or invalid": "Model niedostępny lub nieprawidłowy",
|
||||
"Failed to validate model": "Nie udało się zwalidować modelu",
|
||||
"Couldn't connect to Ollama. Is it running?": "Nie można połączyć się z Ollama. Czy jest uruchomiona?",
|
||||
"Invalid API key or connection failed": "Nieprawidłowy klucz API lub błąd połączenia",
|
||||
"Connection failed": "Połączenie nieudane",
|
||||
"AI Assistant": "Asystent AI",
|
||||
"Enable AI Assistant": "Włącz asystenta AI",
|
||||
"Provider": "Dostawca",
|
||||
"Ollama (Local)": "Ollama (Lokalny)",
|
||||
"AI Gateway (Cloud)": "Brama AI (Chmura)",
|
||||
"Ollama Configuration": "Konfiguracja Ollama",
|
||||
"Refresh Models": "Odśwież modele",
|
||||
"AI Model": "Model AI",
|
||||
"No models detected": "Nie wykryto modeli",
|
||||
"AI Gateway Configuration": "Konfiguracja bramy AI",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Wybierz spośród wysokiej jakości, ekonomicznych modeli AI. Możesz również użyć własnego modelu, wybierając \"Model niestandardowy\" poniżej.",
|
||||
"API Key": "Klucz API",
|
||||
"Get Key": "Pobierz klucz",
|
||||
"Model": "Model",
|
||||
"Custom Model...": "Model niestandardowy...",
|
||||
"Custom Model ID": "ID modelu niestandardowego",
|
||||
"Validate": "Waliduj",
|
||||
"Model available": "Model dostępny",
|
||||
"Connection": "Połączenie",
|
||||
"Test Connection": "Testuj połączenie",
|
||||
"Connected": "Połączono"
|
||||
}
|
||||
|
||||
@@ -884,7 +884,6 @@
|
||||
"Array of annotations": "Lista de anotações",
|
||||
"Highlighted text": "Texto destacado",
|
||||
"Annotation note": "Nota de anotação",
|
||||
"Update time": "Hora de atualização",
|
||||
"Date Format Tokens:": "Tokens de formato de data:",
|
||||
"Year (4 digits)": "Ano (4 dígitos)",
|
||||
"Month (01-12)": "Mês (01-12)",
|
||||
@@ -902,5 +901,50 @@
|
||||
"Show on Discord": "Mostrar no Discord",
|
||||
"Instant {{action}}": "{{action}} instantâneo",
|
||||
"Instant {{action}} Disabled": "{{action}} instantâneo desativado",
|
||||
"Annotation": "Anotação"
|
||||
"Annotation": "Anotação",
|
||||
"Reset Template": "Redefinir modelo",
|
||||
"Annotation style": "Estilo de anotação",
|
||||
"Annotation color": "Cor da anotação",
|
||||
"Annotation time": "Hora da anotação",
|
||||
"AI": "IA",
|
||||
"Are you sure you want to re-index this book?": "Tem certeza de que deseja reindexar este livro?",
|
||||
"Enable AI in Settings": "Ativar IA nas configurações",
|
||||
"Index This Book": "Indexar este livro",
|
||||
"Enable AI search and chat for this book": "Ativar pesquisa e chat com IA para este livro",
|
||||
"Start Indexing": "Iniciar indexação",
|
||||
"Indexing book...": "Indexando livro...",
|
||||
"Preparing...": "Preparando...",
|
||||
"Delete this conversation?": "Excluir esta conversa?",
|
||||
"No conversations yet": "Ainda não há conversas",
|
||||
"Start a new chat to ask questions about this book": "Inicie um novo chat para fazer perguntas sobre este livro",
|
||||
"Rename": "Renomear",
|
||||
"New Chat": "Novo chat",
|
||||
"Chat": "Chat",
|
||||
"Please enter a model ID": "Por favor, insira um ID de modelo",
|
||||
"Model not available or invalid": "Modelo não disponível ou inválido",
|
||||
"Failed to validate model": "Falha ao validar modelo",
|
||||
"Couldn't connect to Ollama. Is it running?": "Não foi possível conectar ao Ollama. Está em execução?",
|
||||
"Invalid API key or connection failed": "Chave API inválida ou falha na conexão",
|
||||
"Connection failed": "Falha na conexão",
|
||||
"AI Assistant": "Assistente de IA",
|
||||
"Enable AI Assistant": "Ativar assistente de IA",
|
||||
"Provider": "Provedor",
|
||||
"Ollama (Local)": "Ollama (Local)",
|
||||
"AI Gateway (Cloud)": "Gateway de IA (Nuvem)",
|
||||
"Ollama Configuration": "Configuração do Ollama",
|
||||
"Refresh Models": "Atualizar modelos",
|
||||
"AI Model": "Modelo de IA",
|
||||
"No models detected": "Nenhum modelo detectado",
|
||||
"AI Gateway Configuration": "Configuração do gateway de IA",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Escolha entre uma seleção de modelos de IA de alta qualidade e econômicos. Você também pode usar seu próprio modelo selecionando \"Modelo personalizado\" abaixo.",
|
||||
"API Key": "Chave API",
|
||||
"Get Key": "Obter chave",
|
||||
"Model": "Modelo",
|
||||
"Custom Model...": "Modelo personalizado...",
|
||||
"Custom Model ID": "ID do modelo personalizado",
|
||||
"Validate": "Validar",
|
||||
"Model available": "Modelo disponível",
|
||||
"Connection": "Conexão",
|
||||
"Test Connection": "Testar conexão",
|
||||
"Connected": "Conectado"
|
||||
}
|
||||
|
||||
@@ -894,7 +894,6 @@
|
||||
"Array of annotations": "Массив примечаний",
|
||||
"Highlighted text": "Выделенный текст",
|
||||
"Annotation note": "Примечание аннотации",
|
||||
"Update time": "Время обновления",
|
||||
"Date Format Tokens:": "Токены формата даты:",
|
||||
"Year (4 digits)": "Год (4 цифры)",
|
||||
"Month (01-12)": "Месяц (01-12)",
|
||||
@@ -912,5 +911,50 @@
|
||||
"Show on Discord": "Показать в Discord",
|
||||
"Instant {{action}}": "Мгновенное {{action}}",
|
||||
"Instant {{action}} Disabled": "Мгновенное {{action}} отключено",
|
||||
"Annotation": "Аннотация"
|
||||
"Annotation": "Аннотация",
|
||||
"Reset Template": "Сбросить шаблон",
|
||||
"Annotation style": "Стиль аннотации",
|
||||
"Annotation color": "Цвет аннотации",
|
||||
"Annotation time": "Время аннотации",
|
||||
"AI": "ИИ",
|
||||
"Are you sure you want to re-index this book?": "Вы уверены, что хотите переиндексировать эту книгу?",
|
||||
"Enable AI in Settings": "Включить ИИ в настройках",
|
||||
"Index This Book": "Индексировать эту книгу",
|
||||
"Enable AI search and chat for this book": "Включить ИИ-поиск и чат для этой книги",
|
||||
"Start Indexing": "Начать индексацию",
|
||||
"Indexing book...": "Индексация книги...",
|
||||
"Preparing...": "Подготовка...",
|
||||
"Delete this conversation?": "Удалить этот разговор?",
|
||||
"No conversations yet": "Пока нет разговоров",
|
||||
"Start a new chat to ask questions about this book": "Начните новый чат, чтобы задать вопросы об этой книге",
|
||||
"Rename": "Переименовать",
|
||||
"New Chat": "Новый чат",
|
||||
"Chat": "Чат",
|
||||
"Please enter a model ID": "Пожалуйста, введите ID модели",
|
||||
"Model not available or invalid": "Модель недоступна или недействительна",
|
||||
"Failed to validate model": "Не удалось проверить модель",
|
||||
"Couldn't connect to Ollama. Is it running?": "Не удалось подключиться к Ollama. Он запущен?",
|
||||
"Invalid API key or connection failed": "Недействительный API-ключ или ошибка подключения",
|
||||
"Connection failed": "Ошибка подключения",
|
||||
"AI Assistant": "ИИ-ассистент",
|
||||
"Enable AI Assistant": "Включить ИИ-ассистента",
|
||||
"Provider": "Провайдер",
|
||||
"Ollama (Local)": "Ollama (Локальный)",
|
||||
"AI Gateway (Cloud)": "ИИ-шлюз (Облако)",
|
||||
"Ollama Configuration": "Настройка Ollama",
|
||||
"Refresh Models": "Обновить модели",
|
||||
"AI Model": "ИИ-модель",
|
||||
"No models detected": "Модели не обнаружены",
|
||||
"AI Gateway Configuration": "Настройка ИИ-шлюза",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Выберите из высококачественных, экономичных ИИ-моделей. Вы также можете использовать свою модель, выбрав \"Пользовательская модель\" ниже.",
|
||||
"API Key": "API-ключ",
|
||||
"Get Key": "Получить ключ",
|
||||
"Model": "Модель",
|
||||
"Custom Model...": "Пользовательская модель...",
|
||||
"Custom Model ID": "ID пользовательской модели",
|
||||
"Validate": "Проверить",
|
||||
"Model available": "Модель доступна",
|
||||
"Connection": "Соединение",
|
||||
"Test Connection": "Проверить соединение",
|
||||
"Connected": "Подключено"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "අනුසටහන් අරය",
|
||||
"Highlighted text": "ඉස්මතු කළ පෙළ",
|
||||
"Annotation note": "අනුසටහන් සටහන",
|
||||
"Update time": "යාවත්කාලීන කාලය",
|
||||
"Date Format Tokens:": "දිනය ආකෘති ටෝකන:",
|
||||
"Year (4 digits)": "වසර (අංක 4)",
|
||||
"Month (01-12)": "මාසය (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Discord හි පෙන්වන්න",
|
||||
"Instant {{action}}": "ක්ෂණික {{action}}",
|
||||
"Instant {{action}} Disabled": "ක්ෂණික {{action}} අබල කර ඇත",
|
||||
"Annotation": "විවරණය"
|
||||
"Annotation": "විවරණය",
|
||||
"Reset Template": "සැකිල්ල නැවත සකස් කරන්න",
|
||||
"Annotation style": "විවරණ විලාසය",
|
||||
"Annotation color": "විවරණ වර්ණය",
|
||||
"Annotation time": "විවරණ වේලාව",
|
||||
"AI": "කෘතිම බුද්ධිය (AI)",
|
||||
"Are you sure you want to re-index this book?": "ඔබට මෙම පොත නැවත දර්ශකය කිරීමට අවශ්ය බව සහතිකද?",
|
||||
"Enable AI in Settings": "සැකසුම් තුළ AI සක්රීය කරන්න",
|
||||
"Index This Book": "මෙම පොත දර්ශකය කරන්න",
|
||||
"Enable AI search and chat for this book": "මෙම පොත සඳහා AI සෙවීම සහ කතාබස් සක්රීය කරන්න",
|
||||
"Start Indexing": "දර්ශකය කිරීම ආරම්භ කරන්න",
|
||||
"Indexing book...": "පොත දර්ශකය කරමින්...",
|
||||
"Preparing...": "සූදානම් වෙමින්...",
|
||||
"Delete this conversation?": "මෙම සංවාදය මකා දමන්නද?",
|
||||
"No conversations yet": "තවම සංවාද නැත",
|
||||
"Start a new chat to ask questions about this book": "මෙම පොත ගැන ප්රශ්න ඇසීමට නව කතාබහක් ආරම්භ කරන්න",
|
||||
"Rename": "නම වෙනස් කරන්න",
|
||||
"New Chat": "නව කතාබහ",
|
||||
"Chat": "කතාබහ",
|
||||
"Please enter a model ID": "කරුණාකර මාදිලි හැඳුනුම්පතක් ඇතුළත් කරන්න",
|
||||
"Model not available or invalid": "මාදිලිය ලබා ගත නොහැක හෝ අවලංගුයි",
|
||||
"Failed to validate model": "මාදිලිය තහවුරු කිරීමට අසමත් විය",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollama වෙත සම්බන්ධ වීමට නොහැකි විය. එය ක්රියාත්මක වේද?",
|
||||
"Invalid API key or connection failed": "අවලංගු API යතුරක් හෝ සම්බන්ධතාවය අසාර්ථක විය",
|
||||
"Connection failed": "සම්බන්ධතාවය අසාර්ථක විය",
|
||||
"AI Assistant": "AI සහායකයා",
|
||||
"Enable AI Assistant": "AI සහායකයා සක්රීය කරන්න",
|
||||
"Provider": "සපයන්නා",
|
||||
"Ollama (Local)": "Ollama (දේශීය)",
|
||||
"AI Gateway (Cloud)": "AI Gateway (Cloud)",
|
||||
"Ollama Configuration": "Ollama වින්යාසය",
|
||||
"Refresh Models": "මාදිලි යාවත්කාලීන කරන්න",
|
||||
"AI Model": "AI මාදිලිය",
|
||||
"No models detected": "කිසිදු මාදිලියක් හඳුනාගෙන නැත",
|
||||
"AI Gateway Configuration": "AI Gateway වින්යාසය",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "උසස් තත්ත්වයේ, ලාභදායී AI මාදිලි එකතුවකින් තෝරන්න. පහතින් \"අභිරුචි මාදිලිය\" තේරීමෙන් ඔබට ඔබේම මාදිලියක් ද ගෙන ඒමට හැකිය.",
|
||||
"API Key": "API යතුර",
|
||||
"Get Key": "යතුර ලබා ගන්න",
|
||||
"Model": "මාදිලිය",
|
||||
"Custom Model...": "අභිරුචි මාදිලිය...",
|
||||
"Custom Model ID": "අභිරුචි මාදිලි හැඳුනුම්පත",
|
||||
"Validate": "තහවුරු කරන්න",
|
||||
"Model available": "මාදිලිය ලබා ගත හැකිය",
|
||||
"Connection": "සම්බන්ධතාවය",
|
||||
"Test Connection": "සම්බන්ධතාවය පරීක්ෂා කරන්න",
|
||||
"Connected": "සම්බන්ධ විය"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "Lista med anteckningar",
|
||||
"Highlighted text": "Markerad text",
|
||||
"Annotation note": "Anteckningsnotering",
|
||||
"Update time": "Uppdateringstid",
|
||||
"Date Format Tokens:": "Datumformattecken:",
|
||||
"Year (4 digits)": "År (4 siffror)",
|
||||
"Month (01-12)": "Månad (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Visa på Discord",
|
||||
"Instant {{action}}": "Omedelbar {{action}}",
|
||||
"Instant {{action}} Disabled": "Omedelbar {{action}} inaktiverad",
|
||||
"Annotation": "Anteckning"
|
||||
"Annotation": "Anteckning",
|
||||
"Reset Template": "Återställ mall",
|
||||
"Annotation style": "Anteckningsstil",
|
||||
"Annotation color": "Anteckningsfärg",
|
||||
"Annotation time": "Anteckningstid",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "Är du säker på att du vill indexera om denna bok?",
|
||||
"Enable AI in Settings": "Aktivera AI i inställningar",
|
||||
"Index This Book": "Indexera denna bok",
|
||||
"Enable AI search and chat for this book": "Aktivera AI-sökning och chatt för denna bok",
|
||||
"Start Indexing": "Starta indexering",
|
||||
"Indexing book...": "Indexerar bok...",
|
||||
"Preparing...": "Förbereder...",
|
||||
"Delete this conversation?": "Ta bort denna konversation?",
|
||||
"No conversations yet": "Inga konversationer ännu",
|
||||
"Start a new chat to ask questions about this book": "Starta en ny chatt för att ställa frågor om denna bok",
|
||||
"Rename": "Byt namn",
|
||||
"New Chat": "Ny chatt",
|
||||
"Chat": "Chatt",
|
||||
"Please enter a model ID": "Ange ett modell-ID",
|
||||
"Model not available or invalid": "Modell ej tillgänglig eller ogiltig",
|
||||
"Failed to validate model": "Misslyckades att validera modell",
|
||||
"Couldn't connect to Ollama. Is it running?": "Kunde inte ansluta till Ollama. Körs den?",
|
||||
"Invalid API key or connection failed": "Ogiltig API-nyckel eller anslutningen misslyckades",
|
||||
"Connection failed": "Anslutningen misslyckades",
|
||||
"AI Assistant": "AI-assistent",
|
||||
"Enable AI Assistant": "Aktivera AI-assistent",
|
||||
"Provider": "Leverantör",
|
||||
"Ollama (Local)": "Ollama (Lokal)",
|
||||
"AI Gateway (Cloud)": "AI-gateway (Moln)",
|
||||
"Ollama Configuration": "Ollama-konfiguration",
|
||||
"Refresh Models": "Uppdatera modeller",
|
||||
"AI Model": "AI-modell",
|
||||
"No models detected": "Inga modeller hittades",
|
||||
"AI Gateway Configuration": "AI-gateway-konfiguration",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Välj bland ett urval av högkvalitativa, ekonomiska AI-modeller. Du kan också använda din egen modell genom att välja \"Anpassad modell\" nedan.",
|
||||
"API Key": "API-nyckel",
|
||||
"Get Key": "Hämta nyckel",
|
||||
"Model": "Modell",
|
||||
"Custom Model...": "Anpassad modell...",
|
||||
"Custom Model ID": "Anpassat modell-ID",
|
||||
"Validate": "Validera",
|
||||
"Model available": "Modell tillgänglig",
|
||||
"Connection": "Anslutning",
|
||||
"Test Connection": "Testa anslutning",
|
||||
"Connected": "Ansluten"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "குறிப்புகளின் பட்டியல்",
|
||||
"Highlighted text": "முன்னிலைப்படுத்தப்பட்ட உரை",
|
||||
"Annotation note": "குறிப்பு குறிப்பு",
|
||||
"Update time": "புதுப்பிப்பு நேரம்",
|
||||
"Date Format Tokens:": "தேதி வடிவமைப்பு டோக்கன்கள்:",
|
||||
"Year (4 digits)": "ஆண்டு (4 இலக்கங்கள்)",
|
||||
"Month (01-12)": "மாதம் (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Discord இல் காட்டு",
|
||||
"Instant {{action}}": "உடனடி {{action}}",
|
||||
"Instant {{action}} Disabled": "உடனடி {{action}} முடக்கப்பட்டது",
|
||||
"Annotation": "குறிப்பு"
|
||||
"Annotation": "குறிப்பு",
|
||||
"Reset Template": "வார்ப்புருவை மீட்டமைக்கவும்",
|
||||
"Annotation style": "சிறுகுறிப்பு பாணி",
|
||||
"Annotation color": "சிறுகுறிப்பு நிறம்",
|
||||
"Annotation time": "சிறுகுறிப்பு நேரம்",
|
||||
"AI": "செயற்கை நுண்ணறிவு (AI)",
|
||||
"Are you sure you want to re-index this book?": "இந்த புத்தகத்தை மீண்டும் அட்டவணைப்படுத்த உறுதியாக இருக்கிறீர்களா?",
|
||||
"Enable AI in Settings": "அமைப்புகளில் AI ஐ இயக்கவும்",
|
||||
"Index This Book": "இந்த புத்தகத்தை அட்டவணைப்படுத்தவும்",
|
||||
"Enable AI search and chat for this book": "இந்த புத்தகத்திற்கு AI தேடல் மற்றும் அரட்டையை இயக்கவும்",
|
||||
"Start Indexing": "அட்டவணைப்படுத்தலைத் தொடங்கவும்",
|
||||
"Indexing book...": "புத்தகம் அட்டவணைப்படுத்தப்படுகிறது...",
|
||||
"Preparing...": "தயாராகிறது...",
|
||||
"Delete this conversation?": "இந்த உரையாடலை நீக்கவா?",
|
||||
"No conversations yet": "இதுவரை உரையாடல்கள் எதுவும் இல்லை",
|
||||
"Start a new chat to ask questions about this book": "இந்த புத்தகத்தைப் பற்றி கேள்விகள் கேட்க புதிய அரட்டையைத் தொடங்கவும்",
|
||||
"Rename": "மறுபெயரிடு",
|
||||
"New Chat": "புதிய அரட்டை",
|
||||
"Chat": "அரட்டை",
|
||||
"Please enter a model ID": "மாதிரி ஐடியை உள்ளிடவும்",
|
||||
"Model not available or invalid": "மாதிரி கிடைக்கவில்லை அல்லது தவறானது",
|
||||
"Failed to validate model": "மாதிரியைச் சரிபார்க்கத் தவறிவிட்டது",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollama வுடன் இணைக்க முடியவில்லை. அது இயங்குகிறதா?",
|
||||
"Invalid API key or connection failed": "தவறான ஏபிஐ (API) விசை அல்லது இணைப்பு தோல்வியடைந்தது",
|
||||
"Connection failed": "இணைப்பு தோல்வியடைந்தது",
|
||||
"AI Assistant": "AI உதவியாளர்",
|
||||
"Enable AI Assistant": "AI உதவியாளரை இயக்கவும்",
|
||||
"Provider": "வழங்குநர்",
|
||||
"Ollama (Local)": "Ollama (உள்ளூர்)",
|
||||
"AI Gateway (Cloud)": "AI கேட்வே (கிளவுட்)",
|
||||
"Ollama Configuration": "Ollama உள்ளமைவு",
|
||||
"Refresh Models": "மாதிரிகளைப் புதுப்பிக்கவும்",
|
||||
"AI Model": "AI மாதிரி",
|
||||
"No models detected": "மாதிரிகள் எதுவும் கண்டறியப்படவில்லை",
|
||||
"AI Gateway Configuration": "AI கேட்வே உள்ளமைவு",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "உயர்தர, சிக்கனமான AI மாதிரிகளிலிருந்து தேர்ந்தெடுக்கவும். கீழே உள்ள \"தனிப்பயன் மாதிரி\" என்பதைத் தேர்ந்தெடுப்பதன் மூலம் உங்கள் சொந்த மாதிரியையும் கொண்டு வரலாம்.",
|
||||
"API Key": "API விசை",
|
||||
"Get Key": "விசையைப் பெறவும்",
|
||||
"Model": "மாதிரி",
|
||||
"Custom Model...": "தனிப்பயன் மாதிரி...",
|
||||
"Custom Model ID": "தனிப்பயன் மாதிரி ஐடி",
|
||||
"Validate": "சரிபார்க்கவும்",
|
||||
"Model available": "மாதிரி கிடைக்கிறது",
|
||||
"Connection": "இணைப்பு",
|
||||
"Test Connection": "இணைப்பைச் சோதிக்கவும்",
|
||||
"Connected": "இணைக்கப்பட்டது"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "อาร์เรย์ของคำอธิบาย",
|
||||
"Highlighted text": "ข้อความที่ไฮไลต์",
|
||||
"Annotation note": "หมายเหตุคำอธิบาย",
|
||||
"Update time": "เวลาอัปเดต",
|
||||
"Date Format Tokens:": "โทเค็นรูปแบบวันที่:",
|
||||
"Year (4 digits)": "ปี (4 หลัก)",
|
||||
"Month (01-12)": "เดือน (01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "แสดงบน Discord",
|
||||
"Instant {{action}}": "{{action}}ทันที",
|
||||
"Instant {{action}} Disabled": "{{action}}ทันทีถูกปิดใช้งาน",
|
||||
"Annotation": "คำอธิบาย"
|
||||
"Annotation": "คำอธิบาย",
|
||||
"Reset Template": "รีเซ็ตเทมเพลต",
|
||||
"Annotation style": "สไตล์คำอธิบาย",
|
||||
"Annotation color": "สีคำอธิบาย",
|
||||
"Annotation time": "เวลาคำอธิบาย",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "คุณแน่ใจหรือไม่ว่าต้องการสร้างดัชนีหนังสือเล่มนี้ใหม่?",
|
||||
"Enable AI in Settings": "เปิดใช้งาน AI ในการตั้งค่า",
|
||||
"Index This Book": "สร้างดัชนีหนังสือเล่มนี้",
|
||||
"Enable AI search and chat for this book": "เปิดใช้งานการค้นหา AI และแชทสำหรับหนังสือเล่มนี้",
|
||||
"Start Indexing": "เริ่มสร้างดัชนี",
|
||||
"Indexing book...": "กำลังสร้างดัชนีหนังสือ...",
|
||||
"Preparing...": "กำลังเตรียม...",
|
||||
"Delete this conversation?": "ลบการสนทนานี้?",
|
||||
"No conversations yet": "ยังไม่มีการสนทนา",
|
||||
"Start a new chat to ask questions about this book": "เริ่มแชทใหม่เพื่อถามคำถามเกี่ยวกับหนังสือเล่มนี้",
|
||||
"Rename": "เปลี่ยนชื่อ",
|
||||
"New Chat": "แชทใหม่",
|
||||
"Chat": "แชท",
|
||||
"Please enter a model ID": "กรุณาป้อน ID โมเดล",
|
||||
"Model not available or invalid": "โมเดลไม่พร้อมใช้งานหรือไม่ถูกต้อง",
|
||||
"Failed to validate model": "ไม่สามารถตรวจสอบโมเดลได้",
|
||||
"Couldn't connect to Ollama. Is it running?": "ไม่สามารถเชื่อมต่อกับ Ollama ได้ กำลังทำงานอยู่หรือไม่?",
|
||||
"Invalid API key or connection failed": "คีย์ API ไม่ถูกต้องหรือการเชื่อมต่อล้มเหลว",
|
||||
"Connection failed": "การเชื่อมต่อล้มเหลว",
|
||||
"AI Assistant": "ผู้ช่วย AI",
|
||||
"Enable AI Assistant": "เปิดใช้งานผู้ช่วย AI",
|
||||
"Provider": "ผู้ให้บริการ",
|
||||
"Ollama (Local)": "Ollama (ในเครื่อง)",
|
||||
"AI Gateway (Cloud)": "เกตเวย์ AI (คลาวด์)",
|
||||
"Ollama Configuration": "การกำหนดค่า Ollama",
|
||||
"Refresh Models": "รีเฟรชโมเดล",
|
||||
"AI Model": "โมเดล AI",
|
||||
"No models detected": "ไม่พบโมเดล",
|
||||
"AI Gateway Configuration": "การกำหนดค่าเกตเวย์ AI",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "เลือกจากโมเดล AI คุณภาพสูงและประหยัด คุณยังสามารถใช้โมเดลของคุณเองโดยเลือก \"โมเดลกำหนดเอง\" ด้านล่าง",
|
||||
"API Key": "คีย์ API",
|
||||
"Get Key": "รับคีย์",
|
||||
"Model": "โมเดล",
|
||||
"Custom Model...": "โมเดลกำหนดเอง...",
|
||||
"Custom Model ID": "ID โมเดลกำหนดเอง",
|
||||
"Validate": "ตรวจสอบ",
|
||||
"Model available": "โมเดลพร้อมใช้งาน",
|
||||
"Connection": "การเชื่อมต่อ",
|
||||
"Test Connection": "ทดสอบการเชื่อมต่อ",
|
||||
"Connected": "เชื่อมต่อแล้ว"
|
||||
}
|
||||
|
||||
@@ -874,7 +874,6 @@
|
||||
"Array of annotations": "Notlar dizisi",
|
||||
"Highlighted text": "Vurgulanan metin",
|
||||
"Annotation note": "Not açıklaması",
|
||||
"Update time": "Güncelleme zamanı",
|
||||
"Date Format Tokens:": "Tarih Biçimi Belirteçleri:",
|
||||
"Year (4 digits)": "Yıl (4 basamak)",
|
||||
"Month (01-12)": "Ay (01-12)",
|
||||
@@ -892,5 +891,50 @@
|
||||
"Show on Discord": "Discord'da göster",
|
||||
"Instant {{action}}": "Anında {{action}}",
|
||||
"Instant {{action}} Disabled": "Anında {{action}} Devre Dışı",
|
||||
"Annotation": "Açıklama"
|
||||
"Annotation": "Açıklama",
|
||||
"Reset Template": "Şablonu Sıfırla",
|
||||
"Annotation style": "Açıklama stili",
|
||||
"Annotation color": "Açıklama rengi",
|
||||
"Annotation time": "Açıklama zamanı",
|
||||
"AI": "YZ",
|
||||
"Are you sure you want to re-index this book?": "Bu kitabı yeniden dizinlemek istediğinizden emin misiniz?",
|
||||
"Enable AI in Settings": "Ayarlarda YZ'yi Etkinleştir",
|
||||
"Index This Book": "Bu Kitabı Dizinle",
|
||||
"Enable AI search and chat for this book": "Bu kitap için YZ arama ve sohbeti etkinleştir",
|
||||
"Start Indexing": "Dizinlemeyi Başlat",
|
||||
"Indexing book...": "Kitap dizinleniyor...",
|
||||
"Preparing...": "Hazırlanıyor...",
|
||||
"Delete this conversation?": "Bu konuşmayı sil?",
|
||||
"No conversations yet": "Henüz konuşma yok",
|
||||
"Start a new chat to ask questions about this book": "Bu kitap hakkında soru sormak için yeni bir sohbet başlatın",
|
||||
"Rename": "Yeniden Adlandır",
|
||||
"New Chat": "Yeni Sohbet",
|
||||
"Chat": "Sohbet",
|
||||
"Please enter a model ID": "Lütfen bir model kimliği girin",
|
||||
"Model not available or invalid": "Model kullanılamıyor veya geçersiz",
|
||||
"Failed to validate model": "Model doğrulanamadı",
|
||||
"Couldn't connect to Ollama. Is it running?": "Ollama'ya bağlanılamadı. Çalışıyor mu?",
|
||||
"Invalid API key or connection failed": "Geçersiz API anahtarı veya bağlantı başarısız",
|
||||
"Connection failed": "Bağlantı başarısız",
|
||||
"AI Assistant": "YZ Asistanı",
|
||||
"Enable AI Assistant": "YZ Asistanını Etkinleştir",
|
||||
"Provider": "Sağlayıcı",
|
||||
"Ollama (Local)": "Ollama (Yerel)",
|
||||
"AI Gateway (Cloud)": "YZ Geçidi (Bulut)",
|
||||
"Ollama Configuration": "Ollama Yapılandırması",
|
||||
"Refresh Models": "Modelleri Yenile",
|
||||
"AI Model": "YZ Modeli",
|
||||
"No models detected": "Model algılanmadı",
|
||||
"AI Gateway Configuration": "YZ Geçidi Yapılandırması",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Yüksek kaliteli, ekonomik YZ modelleri arasından seçim yapın. Aşağıdaki \"Özel Model\"i seçerek kendi modelinizi de kullanabilirsiniz.",
|
||||
"API Key": "API Anahtarı",
|
||||
"Get Key": "Anahtar Al",
|
||||
"Model": "Model",
|
||||
"Custom Model...": "Özel Model...",
|
||||
"Custom Model ID": "Özel Model Kimliği",
|
||||
"Validate": "Doğrula",
|
||||
"Model available": "Model mevcut",
|
||||
"Connection": "Bağlantı",
|
||||
"Test Connection": "Bağlantıyı Test Et",
|
||||
"Connected": "Bağlandı"
|
||||
}
|
||||
|
||||
@@ -894,7 +894,6 @@
|
||||
"Array of annotations": "Масив приміток",
|
||||
"Highlighted text": "Виділений текст",
|
||||
"Annotation note": "Примітка анотації",
|
||||
"Update time": "Час оновлення",
|
||||
"Date Format Tokens:": "Токени формату дати:",
|
||||
"Year (4 digits)": "Рік (4 цифри)",
|
||||
"Month (01-12)": "Місяць (01-12)",
|
||||
@@ -912,5 +911,50 @@
|
||||
"Show on Discord": "Показати в Discord",
|
||||
"Instant {{action}}": "Миттєва {{action}}",
|
||||
"Instant {{action}} Disabled": "Миттєву {{action}} вимкнено",
|
||||
"Annotation": "Анотація"
|
||||
"Annotation": "Анотація",
|
||||
"Reset Template": "Скинути шаблон",
|
||||
"Annotation style": "Стиль анотації",
|
||||
"Annotation color": "Колір анотації",
|
||||
"Annotation time": "Час анотації",
|
||||
"AI": "ШІ",
|
||||
"Are you sure you want to re-index this book?": "Ви впевнені, що хочете переіндексувати цю книгу?",
|
||||
"Enable AI in Settings": "Увімкнути ШІ в налаштуваннях",
|
||||
"Index This Book": "Індексувати цю книгу",
|
||||
"Enable AI search and chat for this book": "Увімкнути ШІ-пошук та чат для цієї книги",
|
||||
"Start Indexing": "Почати індексацію",
|
||||
"Indexing book...": "Індексація книги...",
|
||||
"Preparing...": "Підготовка...",
|
||||
"Delete this conversation?": "Видалити цю розмову?",
|
||||
"No conversations yet": "Поки немає розмов",
|
||||
"Start a new chat to ask questions about this book": "Почніть новий чат, щоб задати питання про цю книгу",
|
||||
"Rename": "Перейменувати",
|
||||
"New Chat": "Новий чат",
|
||||
"Chat": "Чат",
|
||||
"Please enter a model ID": "Будь ласка, введіть ID моделі",
|
||||
"Model not available or invalid": "Модель недоступна або недійсна",
|
||||
"Failed to validate model": "Не вдалося перевірити модель",
|
||||
"Couldn't connect to Ollama. Is it running?": "Не вдалося підключитися до Ollama. Чи вона запущена?",
|
||||
"Invalid API key or connection failed": "Недійсний API-ключ або помилка підключення",
|
||||
"Connection failed": "Помилка підключення",
|
||||
"AI Assistant": "ШІ-асистент",
|
||||
"Enable AI Assistant": "Увімкнути ШІ-асистента",
|
||||
"Provider": "Провайдер",
|
||||
"Ollama (Local)": "Ollama (Локальний)",
|
||||
"AI Gateway (Cloud)": "ШІ-шлюз (Хмара)",
|
||||
"Ollama Configuration": "Налаштування Ollama",
|
||||
"Refresh Models": "Оновити моделі",
|
||||
"AI Model": "ШІ-модель",
|
||||
"No models detected": "Моделі не знайдено",
|
||||
"AI Gateway Configuration": "Налаштування ШІ-шлюзу",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Оберіть з високоякісних, економічних ШІ-моделей. Ви також можете використати власну модель, обравши \"Користувацька модель\" нижче.",
|
||||
"API Key": "API-ключ",
|
||||
"Get Key": "Отримати ключ",
|
||||
"Model": "Модель",
|
||||
"Custom Model...": "Користувацька модель...",
|
||||
"Custom Model ID": "ID користувацької моделі",
|
||||
"Validate": "Перевірити",
|
||||
"Model available": "Модель доступна",
|
||||
"Connection": "З'єднання",
|
||||
"Test Connection": "Перевірити з'єднання",
|
||||
"Connected": "Підключено"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "Danh sách chú thích",
|
||||
"Highlighted text": "Văn bản được đánh dấu",
|
||||
"Annotation note": "Ghi chú chú thích",
|
||||
"Update time": "Thời gian cập nhật",
|
||||
"Date Format Tokens:": "Token định dạng ngày:",
|
||||
"Year (4 digits)": "Năm (4 chữ số)",
|
||||
"Month (01-12)": "Tháng (01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "Hiện trên Discord",
|
||||
"Instant {{action}}": "{{action}} tức thì",
|
||||
"Instant {{action}} Disabled": "{{action}} tức thì đã tắt",
|
||||
"Annotation": "Chú thích"
|
||||
"Annotation": "Chú thích",
|
||||
"Reset Template": "Đặt lại mẫu",
|
||||
"Annotation style": "Kiểu chú thích",
|
||||
"Annotation color": "Màu chú thích",
|
||||
"Annotation time": "Thời gian chú thích",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "Bạn có chắc muốn lập chỉ mục lại cuốn sách này?",
|
||||
"Enable AI in Settings": "Bật AI trong Cài đặt",
|
||||
"Index This Book": "Lập chỉ mục sách này",
|
||||
"Enable AI search and chat for this book": "Bật tìm kiếm AI và trò chuyện cho cuốn sách này",
|
||||
"Start Indexing": "Bắt đầu lập chỉ mục",
|
||||
"Indexing book...": "Đang lập chỉ mục sách...",
|
||||
"Preparing...": "Đang chuẩn bị...",
|
||||
"Delete this conversation?": "Xóa cuộc trò chuyện này?",
|
||||
"No conversations yet": "Chưa có cuộc trò chuyện nào",
|
||||
"Start a new chat to ask questions about this book": "Bắt đầu cuộc trò chuyện mới để hỏi về cuốn sách này",
|
||||
"Rename": "Đổi tên",
|
||||
"New Chat": "Cuộc trò chuyện mới",
|
||||
"Chat": "Trò chuyện",
|
||||
"Please enter a model ID": "Vui lòng nhập ID mô hình",
|
||||
"Model not available or invalid": "Mô hình không khả dụng hoặc không hợp lệ",
|
||||
"Failed to validate model": "Xác thực mô hình thất bại",
|
||||
"Couldn't connect to Ollama. Is it running?": "Không thể kết nối với Ollama. Nó có đang chạy không?",
|
||||
"Invalid API key or connection failed": "Khóa API không hợp lệ hoặc kết nối thất bại",
|
||||
"Connection failed": "Kết nối thất bại",
|
||||
"AI Assistant": "Trợ lý AI",
|
||||
"Enable AI Assistant": "Bật trợ lý AI",
|
||||
"Provider": "Nhà cung cấp",
|
||||
"Ollama (Local)": "Ollama (Cục bộ)",
|
||||
"AI Gateway (Cloud)": "Cổng AI (Đám mây)",
|
||||
"Ollama Configuration": "Cấu hình Ollama",
|
||||
"Refresh Models": "Làm mới mô hình",
|
||||
"AI Model": "Mô hình AI",
|
||||
"No models detected": "Không phát hiện mô hình nào",
|
||||
"AI Gateway Configuration": "Cấu hình cổng AI",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "Chọn từ các mô hình AI chất lượng cao, tiết kiệm. Bạn cũng có thể sử dụng mô hình riêng bằng cách chọn \"Mô hình tùy chỉnh\" bên dưới.",
|
||||
"API Key": "Khóa API",
|
||||
"Get Key": "Lấy khóa",
|
||||
"Model": "Mô hình",
|
||||
"Custom Model...": "Mô hình tùy chỉnh...",
|
||||
"Custom Model ID": "ID mô hình tùy chỉnh",
|
||||
"Validate": "Xác thực",
|
||||
"Model available": "Mô hình khả dụng",
|
||||
"Connection": "Kết nối",
|
||||
"Test Connection": "Kiểm tra kết nối",
|
||||
"Connected": "Đã kết nối"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "标注数组",
|
||||
"Highlighted text": "高亮文本",
|
||||
"Annotation note": "标注笔记",
|
||||
"Update time": "更新时间",
|
||||
"Date Format Tokens:": "日期格式标记:",
|
||||
"Year (4 digits)": "年(4位)",
|
||||
"Month (01-12)": "月(01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "在Discord显示",
|
||||
"Instant {{action}}": "即时{{action}}",
|
||||
"Instant {{action}} Disabled": "即时{{action}}已禁用",
|
||||
"Annotation": "标注"
|
||||
"Annotation": "标注",
|
||||
"Reset Template": "重置模板",
|
||||
"Annotation style": "标注样式",
|
||||
"Annotation color": "标注颜色",
|
||||
"Annotation time": "标注时间",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "确定要重新索引这本书吗?",
|
||||
"Enable AI in Settings": "在设置中启用 AI",
|
||||
"Index This Book": "索引这本书",
|
||||
"Enable AI search and chat for this book": "为这本书启用 AI 搜索和聊天",
|
||||
"Start Indexing": "开始索引",
|
||||
"Indexing book...": "正在索引书籍...",
|
||||
"Preparing...": "准备中...",
|
||||
"Delete this conversation?": "删除此对话?",
|
||||
"No conversations yet": "暂无对话",
|
||||
"Start a new chat to ask questions about this book": "开始新对话来询问关于这本书的问题",
|
||||
"Rename": "重命名",
|
||||
"New Chat": "新对话",
|
||||
"Chat": "聊天",
|
||||
"Please enter a model ID": "请输入模型 ID",
|
||||
"Model not available or invalid": "模型不可用或无效",
|
||||
"Failed to validate model": "模型验证失败",
|
||||
"Couldn't connect to Ollama. Is it running?": "无法连接到 Ollama。它是否正在运行?",
|
||||
"Invalid API key or connection failed": "API 密钥无效或连接失败",
|
||||
"Connection failed": "连接失败",
|
||||
"AI Assistant": "AI 助手",
|
||||
"Enable AI Assistant": "启用 AI 助手",
|
||||
"Provider": "提供商",
|
||||
"Ollama (Local)": "Ollama(本地)",
|
||||
"AI Gateway (Cloud)": "AI 网关(云端)",
|
||||
"Ollama Configuration": "Ollama 配置",
|
||||
"Refresh Models": "刷新模型",
|
||||
"AI Model": "AI 模型",
|
||||
"No models detected": "未检测到模型",
|
||||
"AI Gateway Configuration": "AI 网关配置",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "从一系列高质量、经济实惠的 AI 模型中选择。您也可以通过下方的\"自定义模型\"使用自己的模型。",
|
||||
"API Key": "API 密钥",
|
||||
"Get Key": "获取密钥",
|
||||
"Model": "模型",
|
||||
"Custom Model...": "自定义模型...",
|
||||
"Custom Model ID": "自定义模型 ID",
|
||||
"Validate": "验证",
|
||||
"Model available": "模型可用",
|
||||
"Connection": "连接",
|
||||
"Test Connection": "测试连接",
|
||||
"Connected": "已连接"
|
||||
}
|
||||
|
||||
@@ -864,7 +864,6 @@
|
||||
"Array of annotations": "標註陣列",
|
||||
"Highlighted text": "標記文字",
|
||||
"Annotation note": "標註筆記",
|
||||
"Update time": "更新時間",
|
||||
"Date Format Tokens:": "日期格式標記:",
|
||||
"Year (4 digits)": "年(4位)",
|
||||
"Month (01-12)": "月(01-12)",
|
||||
@@ -882,5 +881,50 @@
|
||||
"Show on Discord": "在Discord顯示",
|
||||
"Instant {{action}}": "即時{{action}}",
|
||||
"Instant {{action}} Disabled": "即時{{action}}已停用",
|
||||
"Annotation": "註解"
|
||||
"Annotation": "註解",
|
||||
"Reset Template": "重置範本",
|
||||
"Annotation style": "標註樣式",
|
||||
"Annotation color": "標註顏色",
|
||||
"Annotation time": "標註時間",
|
||||
"AI": "AI",
|
||||
"Are you sure you want to re-index this book?": "確定要重新索引這本書嗎?",
|
||||
"Enable AI in Settings": "在設定中啟用 AI",
|
||||
"Index This Book": "索引這本書",
|
||||
"Enable AI search and chat for this book": "為這本書啟用 AI 搜尋和聊天",
|
||||
"Start Indexing": "開始索引",
|
||||
"Indexing book...": "正在索引書籍...",
|
||||
"Preparing...": "準備中...",
|
||||
"Delete this conversation?": "刪除此對話?",
|
||||
"No conversations yet": "尚無對話",
|
||||
"Start a new chat to ask questions about this book": "開始新對話來詢問關於這本書的問題",
|
||||
"Rename": "重新命名",
|
||||
"New Chat": "新對話",
|
||||
"Chat": "聊天",
|
||||
"Please enter a model ID": "請輸入模型 ID",
|
||||
"Model not available or invalid": "模型不可用或無效",
|
||||
"Failed to validate model": "模型驗證失敗",
|
||||
"Couldn't connect to Ollama. Is it running?": "無法連線到 Ollama。它是否正在執行?",
|
||||
"Invalid API key or connection failed": "API 金鑰無效或連線失敗",
|
||||
"Connection failed": "連線失敗",
|
||||
"AI Assistant": "AI 助手",
|
||||
"Enable AI Assistant": "啟用 AI 助手",
|
||||
"Provider": "提供者",
|
||||
"Ollama (Local)": "Ollama(本機)",
|
||||
"AI Gateway (Cloud)": "AI 閘道(雲端)",
|
||||
"Ollama Configuration": "Ollama 設定",
|
||||
"Refresh Models": "重新整理模型",
|
||||
"AI Model": "AI 模型",
|
||||
"No models detected": "未偵測到模型",
|
||||
"AI Gateway Configuration": "AI 閘道設定",
|
||||
"Choose from a selection of high-quality, economical AI models. You can also bring your own model by selecting \"Custom Model\" below.": "從一系列高品質、經濟實惠的 AI 模型中選擇。您也可以透過下方的「自訂模型」使用自己的模型。",
|
||||
"API Key": "API 金鑰",
|
||||
"Get Key": "取得金鑰",
|
||||
"Model": "模型",
|
||||
"Custom Model...": "自訂模型...",
|
||||
"Custom Model ID": "自訂模型 ID",
|
||||
"Validate": "驗證",
|
||||
"Model available": "模型可用",
|
||||
"Connection": "連線",
|
||||
"Test Connection": "測試連線",
|
||||
"Connected": "已連線"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,572 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { renderNoteTemplate, validateNoteTemplate, NoteTemplateData } from '../../utils/note';
|
||||
|
||||
describe('renderNoteTemplate', () => {
|
||||
const sampleData: NoteTemplateData = {
|
||||
title: 'The Great Gatsby',
|
||||
author: 'F. Scott Fitzgerald',
|
||||
exportDate: '2024-01-15',
|
||||
chapters: [
|
||||
{
|
||||
title: 'Chapter 1',
|
||||
annotations: [
|
||||
{
|
||||
text: 'In my younger and more vulnerable years',
|
||||
note: 'Opening line',
|
||||
style: 'highlight',
|
||||
color: 'yellow',
|
||||
timestamp: 1705312800000, // 2024-01-15 10:00:00 UTC
|
||||
},
|
||||
{
|
||||
text: 'So we beat on, boats against the current',
|
||||
note: '',
|
||||
style: 'underline',
|
||||
color: 'blue',
|
||||
timestamp: 1705316400000, // 2024-01-15 11:00:00 UTC
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Chapter 2',
|
||||
annotations: [
|
||||
{
|
||||
text: 'The eyes of Doctor T. J. Eckleburg',
|
||||
note: 'Symbolism',
|
||||
style: 'highlight',
|
||||
color: 'green',
|
||||
timestamp: 1705320000000, // 2024-01-15 12:00:00 UTC
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe('Variable substitution', () => {
|
||||
it('should substitute simple variables', () => {
|
||||
const template = 'Book: {{ title }} by {{ author }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Book: The Great Gatsby by F. Scott Fitzgerald');
|
||||
});
|
||||
|
||||
it('should handle undefined variables gracefully', () => {
|
||||
const template = '{{ nonexistent }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should handle nested property access', () => {
|
||||
const template = '{{ chapters[0].title }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Chapter 1');
|
||||
});
|
||||
|
||||
it('should handle deeply nested property access', () => {
|
||||
const template = '{{ chapters[0].annotations[0].text }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('In my younger and more vulnerable years');
|
||||
});
|
||||
});
|
||||
|
||||
describe('For loops', () => {
|
||||
it('should iterate over arrays', () => {
|
||||
const template = '{% for chapter in chapters %}{{ chapter.title }}\n{% endfor %}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toContain('Chapter 1');
|
||||
expect(result).toContain('Chapter 2');
|
||||
});
|
||||
|
||||
it('should handle nested for loops', () => {
|
||||
const template = `{% for chapter in chapters %}
|
||||
## {{ chapter.title }}
|
||||
{% for annotation in chapter.annotations %}
|
||||
- {{ annotation.text }}
|
||||
{% endfor %}
|
||||
{% endfor %}`;
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toContain('## Chapter 1');
|
||||
expect(result).toContain('- In my younger and more vulnerable years');
|
||||
expect(result).toContain('## Chapter 2');
|
||||
expect(result).toContain('- The eyes of Doctor T. J. Eckleburg');
|
||||
});
|
||||
|
||||
it('should handle empty arrays', () => {
|
||||
const emptyData: NoteTemplateData = {
|
||||
title: 'Empty Book',
|
||||
author: 'Nobody',
|
||||
exportDate: '2024-01-15',
|
||||
chapters: [],
|
||||
};
|
||||
const template = '{% for chapter in chapters %}{{ chapter.title }}{% endfor %}';
|
||||
const result = renderNoteTemplate(template, emptyData);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should provide loop variables (loop.index, loop.first, loop.last)', () => {
|
||||
const template = `{% for chapter in chapters %}{{ loop.index }}: {{ chapter.title }}{% if not loop.last %}, {% endif %}{% endfor %}`;
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('1: Chapter 1, 2: Chapter 2');
|
||||
});
|
||||
|
||||
it('should provide loop.index0 (0-based index)', () => {
|
||||
const template = `{% for chapter in chapters %}{{ loop.index0 }}: {{ chapter.title }}\n{% endfor %}`;
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toContain('0: Chapter 1');
|
||||
expect(result).toContain('1: Chapter 2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Conditionals', () => {
|
||||
it('should handle if statements', () => {
|
||||
const template = '{% if author %}Author: {{ author }}{% endif %}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Author: F. Scott Fitzgerald');
|
||||
});
|
||||
|
||||
it('should handle if-else statements', () => {
|
||||
const template = '{% if nonexistent %}Has value{% else %}No value{% endif %}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('No value');
|
||||
});
|
||||
|
||||
it('should handle if-elif-else statements', () => {
|
||||
const template =
|
||||
'{% if chapters.length > 5 %}Many{% elif chapters.length > 1 %}Some{% else %}Few{% endif %}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Some');
|
||||
});
|
||||
|
||||
it('should handle if statements with annotation note', () => {
|
||||
const template = `{% for chapter in chapters %}{% for annotation in chapter.annotations %}{% if annotation.note %}Note: {{ annotation.note }}
|
||||
{% endif %}{% endfor %}{% endfor %}`;
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toContain('Note: Opening line');
|
||||
expect(result).toContain('Note: Symbolism');
|
||||
expect(result.match(/Note:/g)?.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Date filter', () => {
|
||||
it('should format timestamp with default locale format', () => {
|
||||
const template = '{{ chapters[0].annotations[0].timestamp | date }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
// Result will be locale-dependent, just check it's not empty
|
||||
expect(result).not.toBe('');
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should format timestamp with custom format %Y-%m-%d', () => {
|
||||
const template = "{{ chapters[0].annotations[0].timestamp | date('%Y-%m-%d') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('2024-01-15');
|
||||
});
|
||||
|
||||
it('should format timestamp with time format %H:%M:%S', () => {
|
||||
const template = "{{ chapters[0].annotations[0].timestamp | date('%H:%M:%S') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
// This depends on timezone, so just check the format
|
||||
expect(result).toMatch(/^\d{2}:\d{2}:\d{2}$/);
|
||||
});
|
||||
|
||||
it('should format timestamp with full datetime', () => {
|
||||
const template = "{{ chapters[0].annotations[0].timestamp | date('%Y-%m-%d %H:%M') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toMatch(/^2024-01-15 \d{2}:\d{2}$/);
|
||||
});
|
||||
|
||||
it('should handle 12-hour format with %I and %p', () => {
|
||||
const template = "{{ chapters[0].annotations[0].timestamp | date('%I:%M %p') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toMatch(/^\d{2}:\d{2} (AM|PM)$/);
|
||||
});
|
||||
|
||||
it('should handle undefined timestamp', () => {
|
||||
const dataWithoutTimestamp: NoteTemplateData = {
|
||||
...sampleData,
|
||||
chapters: [
|
||||
{
|
||||
title: 'Chapter',
|
||||
annotations: [{ text: 'Text' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
const template = "{{ chapters[0].annotations[0].timestamp | date('%Y-%m-%d') }}";
|
||||
const result = renderNoteTemplate(template, dataWithoutTimestamp);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should handle string date input', () => {
|
||||
const template = "{{ exportDate | date('%Y-%m-%d') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('2024-01-15');
|
||||
});
|
||||
|
||||
it('should handle escaped percent signs', () => {
|
||||
const template =
|
||||
"{{ chapters[0].annotations[0].timestamp | date('100%% complete on %Y-%m-%d') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toContain('100% complete on 2024-01-15');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Default filter', () => {
|
||||
it('should return value when present', () => {
|
||||
const template = "{{ title | default('Unknown') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('The Great Gatsby');
|
||||
});
|
||||
|
||||
it('should return default when value is undefined', () => {
|
||||
const template = "{{ nonexistent | default('Unknown') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Unknown');
|
||||
});
|
||||
|
||||
it('should return default when value is empty string', () => {
|
||||
const template = "{{ chapters[0].annotations[1].note | default('No note') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('No note');
|
||||
});
|
||||
});
|
||||
|
||||
describe('String filters', () => {
|
||||
it('should convert to uppercase with upper filter', () => {
|
||||
const template = '{{ title | upper }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('THE GREAT GATSBY');
|
||||
});
|
||||
|
||||
it('should convert to lowercase with lower filter', () => {
|
||||
const template = '{{ title | lower }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('the great gatsby');
|
||||
});
|
||||
|
||||
it('should capitalize with capitalize filter', () => {
|
||||
const template = '{{ "hello world" | capitalize }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Hello world');
|
||||
});
|
||||
|
||||
it('should title case with title filter', () => {
|
||||
const template = '{{ "hello world" | title }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Hello World');
|
||||
});
|
||||
|
||||
it('should trim whitespace with trim filter', () => {
|
||||
const template = '{{ " spaced " | trim }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('spaced');
|
||||
});
|
||||
|
||||
it('should replace substrings with replace filter', () => {
|
||||
const template = "{{ title | replace('Great', 'Amazing') }}";
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('The Amazing Gatsby');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Truncate filter', () => {
|
||||
it('should truncate long strings', () => {
|
||||
const template = '{{ chapters[0].annotations[0].text | truncate(20) }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result.length).toBeLessThanOrEqual(23); // 20 + '...'
|
||||
expect(result).toContain('...');
|
||||
});
|
||||
|
||||
it('should not truncate short strings', () => {
|
||||
const template = '{{ title | truncate(50) }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('The Great Gatsby');
|
||||
});
|
||||
|
||||
it('should truncate at word boundaries by default', () => {
|
||||
const template = '{{ chapters[0].annotations[0].text | truncate(25) }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).not.toMatch(/\s\.\.\.$/); // Should not end with space before ...
|
||||
});
|
||||
});
|
||||
|
||||
describe('Length filter', () => {
|
||||
it('should return string length', () => {
|
||||
const template = '{{ title | length }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('16');
|
||||
});
|
||||
|
||||
it('should return array length', () => {
|
||||
const template = '{{ chapters | length }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('First and last filters', () => {
|
||||
it('should get first element of array', () => {
|
||||
const template = '{% set first_chapter = chapters | first %}{{ first_chapter.title }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Chapter 1');
|
||||
});
|
||||
|
||||
it('should get last element of array', () => {
|
||||
const template = '{% set last_chapter = chapters | last %}{{ last_chapter.title }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Chapter 2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Join filter', () => {
|
||||
it('should join array elements', () => {
|
||||
// Using a loop with conditional comma separator
|
||||
const template =
|
||||
'{% for chapter in chapters %}{{ chapter.title }}{% if not loop.last %}, {% endif %}{% endfor %}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('Chapter 1, Chapter 2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Newline to BR filter', () => {
|
||||
it('should convert newlines to br tags', () => {
|
||||
const dataWithNewlines: NoteTemplateData = {
|
||||
...sampleData,
|
||||
chapters: [
|
||||
{
|
||||
title: 'Chapter 1',
|
||||
annotations: [
|
||||
{
|
||||
text: 'Line 1\nLine 2\nLine 3',
|
||||
note: 'Multiple lines',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const template = '{{ chapters[0].annotations[0].text | nl2br }}';
|
||||
const result = renderNoteTemplate(template, dataWithNewlines);
|
||||
expect(result).toBe('Line 1<br>\nLine 2<br>\nLine 3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Chained filters', () => {
|
||||
it('should support chaining multiple filters', () => {
|
||||
const template = '{{ title | upper | truncate(10) }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
// truncate(10) with word boundaries results in "THE GREAT..." (breaks at word boundary)
|
||||
expect(result).toBe('THE GREAT...');
|
||||
});
|
||||
|
||||
it('should support chaining with killwords option', () => {
|
||||
const template = '{{ title | upper | truncate(5, true) }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
// truncate(5, true) with killwords results in "THE G..."
|
||||
expect(result).toBe('THE G...');
|
||||
});
|
||||
|
||||
it('should chain date and string filters', () => {
|
||||
const template = '{{ exportDate | upper }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('2024-01-15');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Complete template rendering', () => {
|
||||
it('should render a complete export template', () => {
|
||||
const template = `## {{ title }}
|
||||
**Author**: {{ author }}
|
||||
|
||||
**Exported**: {{ exportDate }}
|
||||
|
||||
---
|
||||
|
||||
### Highlights & Annotations
|
||||
|
||||
{% for chapter in chapters %}
|
||||
#### {{ chapter.title }}
|
||||
{% for annotation in chapter.annotations %}
|
||||
> {{ annotation.text }}
|
||||
{% if annotation.note %}
|
||||
**Note:** {{ annotation.note }}
|
||||
{% endif %}
|
||||
*Time: {{ annotation.timestamp | date('%Y-%m-%d %H:%M') }}*
|
||||
{% endfor %}
|
||||
|
||||
---
|
||||
{% endfor %}`;
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
|
||||
expect(result).toContain('## The Great Gatsby');
|
||||
expect(result).toContain('**Author**: F. Scott Fitzgerald');
|
||||
expect(result).toContain('#### Chapter 1');
|
||||
expect(result).toContain('> In my younger and more vulnerable years');
|
||||
expect(result).toContain('**Note:** Opening line');
|
||||
expect(result).toContain('#### Chapter 2');
|
||||
expect(result).toContain('> The eyes of Doctor T. J. Eckleburg');
|
||||
});
|
||||
|
||||
it('should handle template with no chapters', () => {
|
||||
const emptyData: NoteTemplateData = {
|
||||
title: 'Empty Book',
|
||||
author: 'Unknown',
|
||||
exportDate: '2024-01-15',
|
||||
chapters: [],
|
||||
};
|
||||
const template = `## {{ title }}
|
||||
{% for chapter in chapters %}
|
||||
{{ chapter.title }}
|
||||
{% endfor %}`;
|
||||
const result = renderNoteTemplate(template, emptyData);
|
||||
expect(result).toContain('## Empty Book');
|
||||
expect(result).not.toContain('Chapter');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error handling', () => {
|
||||
it('should handle invalid template syntax gracefully', () => {
|
||||
const template = '{{ unclosed';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toContain('[Template Error:');
|
||||
});
|
||||
|
||||
it('should handle invalid filter', () => {
|
||||
// Nunjucks throws on unknown filters
|
||||
const template = '{{ title | nonexistentfilter }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toContain('[Template Error:');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Special characters and escaping', () => {
|
||||
it('should not auto-escape HTML characters', () => {
|
||||
const dataWithHtml: NoteTemplateData = {
|
||||
...sampleData,
|
||||
title: '<b>Bold</b> Title',
|
||||
};
|
||||
const template = '{{ title }}';
|
||||
const result = renderNoteTemplate(template, dataWithHtml);
|
||||
expect(result).toBe('<b>Bold</b> Title');
|
||||
});
|
||||
|
||||
it('should handle markdown special characters', () => {
|
||||
const dataWithMarkdown: NoteTemplateData = {
|
||||
...sampleData,
|
||||
chapters: [
|
||||
{
|
||||
title: '# Heading with **bold** and _italic_',
|
||||
annotations: [{ text: '> Quoted text' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
const template = '{{ chapters[0].title }}\n{{ chapters[0].annotations[0].text }}';
|
||||
const result = renderNoteTemplate(template, dataWithMarkdown);
|
||||
expect(result).toContain('# Heading with **bold** and _italic_');
|
||||
expect(result).toContain('> Quoted text');
|
||||
});
|
||||
|
||||
it('should handle unicode characters', () => {
|
||||
const dataWithUnicode: NoteTemplateData = {
|
||||
...sampleData,
|
||||
title: '红楼梦',
|
||||
author: '曹雪芹',
|
||||
chapters: [
|
||||
{
|
||||
title: '第一回',
|
||||
annotations: [{ text: '满纸荒唐言,一把辛酸泪。' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
const template = '{{ title }} - {{ author }}: {{ chapters[0].annotations[0].text }}';
|
||||
const result = renderNoteTemplate(template, dataWithUnicode);
|
||||
expect(result).toBe('红楼梦 - 曹雪芹: 满纸荒唐言,一把辛酸泪。');
|
||||
});
|
||||
|
||||
it('should handle emoji', () => {
|
||||
const dataWithEmoji: NoteTemplateData = {
|
||||
...sampleData,
|
||||
title: '📚 My Book',
|
||||
chapters: [
|
||||
{
|
||||
title: 'Chapter 😀',
|
||||
annotations: [{ text: 'Text with emoji 🎉' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
const template = '{{ title }} - {{ chapters[0].annotations[0].text }}';
|
||||
const result = renderNoteTemplate(template, dataWithEmoji);
|
||||
expect(result).toBe('📚 My Book - Text with emoji 🎉');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Whitespace handling', () => {
|
||||
it('should trim blocks correctly', () => {
|
||||
const template = `Start
|
||||
{% if true %}
|
||||
Content
|
||||
{% endif %}
|
||||
End`;
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
// With trimBlocks and lstripBlocks enabled, whitespace should be managed
|
||||
expect(result).toContain('Start');
|
||||
expect(result).toContain('Content');
|
||||
expect(result).toContain('End');
|
||||
});
|
||||
|
||||
it('should preserve intentional whitespace in content', () => {
|
||||
const template = '{{ title }} {{ author }}';
|
||||
const result = renderNoteTemplate(template, sampleData);
|
||||
expect(result).toBe('The Great Gatsby F. Scott Fitzgerald');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateNoteTemplate', () => {
|
||||
it('should return valid for correct template', () => {
|
||||
const template = '{{ title }} by {{ author }}';
|
||||
const result = validateNoteTemplate(template);
|
||||
expect(result.isValid).toBe(true);
|
||||
expect(result.error).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return valid for complex template', () => {
|
||||
const template = `{% for chapter in chapters %}
|
||||
{{ chapter.title }}
|
||||
{% for annotation in chapter.annotations %}
|
||||
{{ annotation.text }}
|
||||
{% endfor %}
|
||||
{% endfor %}`;
|
||||
const result = validateNoteTemplate(template);
|
||||
expect(result.isValid).toBe(true);
|
||||
});
|
||||
|
||||
it('should return invalid for unclosed variable', () => {
|
||||
const template = '{{ unclosed';
|
||||
const result = validateNoteTemplate(template);
|
||||
expect(result.isValid).toBe(false);
|
||||
expect(result.error).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return invalid for unclosed block', () => {
|
||||
const template = '{% if true %}content';
|
||||
const result = validateNoteTemplate(template);
|
||||
expect(result.isValid).toBe(false);
|
||||
expect(result.error).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return invalid for unclosed for loop', () => {
|
||||
const template = '{% for item in items %}content';
|
||||
const result = validateNoteTemplate(template);
|
||||
expect(result.isValid).toBe(false);
|
||||
expect(result.error).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return valid for empty template', () => {
|
||||
const template = '';
|
||||
const result = validateNoteTemplate(template);
|
||||
expect(result.isValid).toBe(true);
|
||||
});
|
||||
|
||||
it('should return valid for plain text without template syntax', () => {
|
||||
const template = 'Just plain text without any template syntax';
|
||||
const result = validateNoteTemplate(template);
|
||||
expect(result.isValid).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,14 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useState, useMemo, useEffect } from 'react';
|
||||
import { marked } from 'marked';
|
||||
import { BookNote, BooknoteGroup, NoteExportConfig } from '@/types/book';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import Dialog from '@/components/Dialog';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { BookNote, BooknoteGroup, NoteExportConfig } from '@/types/book';
|
||||
import { DEFAULT_NOTE_EXPORT_CONFIG } from '@/services/constants';
|
||||
import { saveViewSettings } from '@/helpers/settings';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { renderNoteTemplate } from '@/utils/note';
|
||||
import Dialog from '@/components/Dialog';
|
||||
|
||||
interface ExportMarkdownDialogProps {
|
||||
bookKey: string;
|
||||
@@ -20,135 +21,6 @@ interface ExportMarkdownDialogProps {
|
||||
onExport: (markdown: string) => void;
|
||||
}
|
||||
|
||||
type TemplateData = {
|
||||
title: string;
|
||||
author: string;
|
||||
exportDate: string;
|
||||
chapters: {
|
||||
title: string;
|
||||
annotations: {
|
||||
text: string;
|
||||
note?: string;
|
||||
timestamp?: number;
|
||||
}[];
|
||||
}[];
|
||||
};
|
||||
|
||||
type TemplateVariable = { [key: string]: number | string | TemplateVariable | TemplateVariable[] };
|
||||
|
||||
const renderTemplate = (template: string, data: TemplateData): string => {
|
||||
const applyFilter = (
|
||||
value: TemplateVariable,
|
||||
filter: string,
|
||||
filterArg?: string,
|
||||
): TemplateVariable | string => {
|
||||
if (filter === 'date') {
|
||||
if (typeof value === 'number') {
|
||||
const date = new Date(value);
|
||||
if (filterArg) {
|
||||
const format = filterArg;
|
||||
return format
|
||||
.replace('%Y', date.getFullYear().toString())
|
||||
.replace('%m', String(date.getMonth() + 1).padStart(2, '0'))
|
||||
.replace('%d', String(date.getDate()).padStart(2, '0'))
|
||||
.replace('%H', String(date.getHours()).padStart(2, '0'))
|
||||
.replace('%M', String(date.getMinutes()).padStart(2, '0'))
|
||||
.replace('%S', String(date.getSeconds()).padStart(2, '0'));
|
||||
}
|
||||
return date.toLocaleString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const getValue = (path: string, context: TemplateData) => {
|
||||
const keys = path.trim().split('.');
|
||||
let value = context as TemplateVariable;
|
||||
for (const key of keys) {
|
||||
value = value?.[key] as TemplateVariable;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
let result = template;
|
||||
|
||||
// Process {% for %} loops - find first occurrence and recurse
|
||||
const forMatch = result.match(/\{%\s*for\s+(\w+)\s+in\s+(\w+(?:\.\w+)*)\s*%\}/);
|
||||
if (forMatch) {
|
||||
const itemName = forMatch[1]!;
|
||||
const collectionPath = forMatch[2]!;
|
||||
|
||||
// Find matching {% endfor %} by counting nesting
|
||||
let depth = 0;
|
||||
let endPos = -1;
|
||||
const startPos = forMatch.index! + forMatch[0].length;
|
||||
|
||||
for (let i = startPos; i < result.length; i++) {
|
||||
const remaining = result.slice(i);
|
||||
if (remaining.startsWith('{% for ')) {
|
||||
depth++;
|
||||
i += 6; // skip past "{% for"
|
||||
} else if (remaining.startsWith('{% endfor %}')) {
|
||||
if (depth === 0) {
|
||||
endPos = i;
|
||||
break;
|
||||
}
|
||||
depth--;
|
||||
i += 11; // skip past "{% endfor %}"
|
||||
}
|
||||
}
|
||||
|
||||
if (endPos !== -1) {
|
||||
const beforeLoop = result.slice(0, forMatch.index);
|
||||
const loopContent = result.slice(startPos, endPos);
|
||||
const afterLoop = result.slice(endPos + 13); // 13 = length of "{% endfor %}"
|
||||
|
||||
const collection = getValue(collectionPath, data);
|
||||
|
||||
if (Array.isArray(collection)) {
|
||||
const renderedItems = collection
|
||||
.map((item) => {
|
||||
const loopData = { ...data, [itemName]: item };
|
||||
return renderTemplate(loopContent, loopData);
|
||||
})
|
||||
.join('');
|
||||
|
||||
result = beforeLoop + renderedItems + afterLoop;
|
||||
return renderTemplate(result, data);
|
||||
} else {
|
||||
// Collection not found or not an array, remove the loop
|
||||
result = beforeLoop + afterLoop;
|
||||
return renderTemplate(result, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process {% if condition %}...{% endif %}
|
||||
result = result.replace(
|
||||
/\{%\s*if\s+([^%]+?)\s*%\}([\s\S]*?)\{%\s*endif\s*%\}/g,
|
||||
(_match, condition, content) => {
|
||||
const value = getValue(condition, data);
|
||||
return value ? renderTemplate(content, data) : '';
|
||||
},
|
||||
);
|
||||
|
||||
// Replace {{ variable }}, {{ variable | filter }}, and {{ variable | filter('arg') }}
|
||||
result = result.replace(
|
||||
/\{\{\s*([^}|]+?)(?:\s*\|\s*(\w+)(?:\s*\((['"]?)([^)'"]*)\3\))?)?\s*\}\}/g,
|
||||
(_match, path, filter, _quote, filterArg) => {
|
||||
const value = getValue(path, data);
|
||||
if (value === undefined || value === null) return '';
|
||||
if (filter) {
|
||||
return applyFilter(value, filter, filterArg) as string;
|
||||
}
|
||||
return String(value);
|
||||
},
|
||||
);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const ExportMarkdownDialog: React.FC<ExportMarkdownDialogProps> = ({
|
||||
bookKey,
|
||||
isOpen,
|
||||
@@ -167,7 +39,7 @@ const ExportMarkdownDialog: React.FC<ExportMarkdownDialogProps> = ({
|
||||
const defaultTemplate = `## {{ title }}
|
||||
**${_('Author')}**: {{ author }}
|
||||
|
||||
**${_('Exported from Readest')}**: {{ exportDate }}
|
||||
**${_('Exported from Readest')}**: {{ exportDate | date('%Y-%m-%d') }}
|
||||
|
||||
---
|
||||
|
||||
@@ -176,7 +48,19 @@ const ExportMarkdownDialog: React.FC<ExportMarkdownDialogProps> = ({
|
||||
{% for chapter in chapters %}
|
||||
#### {{ chapter.title }}
|
||||
{% for annotation in chapter.annotations %}
|
||||
> {{ annotation.text }}
|
||||
{% if annotation.color == 'yellow' %}
|
||||
- {{ annotation.text }}
|
||||
{% elif annotation.color == 'red' %}
|
||||
- ❗ {{ annotation.text }}
|
||||
{% elif annotation.color == 'green' %}
|
||||
- ✅ {{ annotation.text }}
|
||||
{% elif annotation.color == 'blue' %}
|
||||
- 💡 {{ annotation.text }}
|
||||
{% elif annotation.color == 'violet' %}
|
||||
- ✨ {{ annotation.text }}
|
||||
{% else %}
|
||||
- {{ annotation.text }}
|
||||
{% endif %}
|
||||
{% if annotation.note %}
|
||||
**${_('Note:')}** {{ annotation.note }}
|
||||
{% endif %}
|
||||
@@ -219,7 +103,7 @@ const ExportMarkdownDialog: React.FC<ExportMarkdownDialogProps> = ({
|
||||
const templateData = {
|
||||
title: bookTitle,
|
||||
author: bookAuthor,
|
||||
exportDate: new Date().toISOString().slice(0, 10),
|
||||
exportDate: new Date().getTime(),
|
||||
chapters: sortedGroups.map((group) => ({
|
||||
title: group.label || _('Untitled'),
|
||||
annotations: group.booknotes.map((note) => ({
|
||||
@@ -232,7 +116,7 @@ const ExportMarkdownDialog: React.FC<ExportMarkdownDialogProps> = ({
|
||||
})),
|
||||
};
|
||||
|
||||
return renderTemplate(exportConfig.customTemplate, templateData);
|
||||
return renderNoteTemplate(exportConfig.customTemplate, templateData);
|
||||
}
|
||||
|
||||
// Default formatting (non-template mode)
|
||||
@@ -456,7 +340,17 @@ const ExportMarkdownDialog: React.FC<ExportMarkdownDialogProps> = ({
|
||||
{exportConfig.useCustomTemplate && (
|
||||
<>
|
||||
<div className='space-y-2'>
|
||||
<label className='text-sm font-medium'>{_('Export Template')}</label>
|
||||
<div className='flex items-center justify-between'>
|
||||
<label className='text-sm font-medium'>{_('Export Template')}</label>
|
||||
<button
|
||||
onClick={() =>
|
||||
setExportConfig({ ...exportConfig, customTemplate: defaultTemplate })
|
||||
}
|
||||
className='text-sm text-blue-500 hover:underline'
|
||||
>
|
||||
{_('Reset Template')}
|
||||
</button>
|
||||
</div>
|
||||
<textarea
|
||||
value={exportConfig.customTemplate}
|
||||
onChange={(e) =>
|
||||
@@ -537,9 +431,17 @@ const ExportMarkdownDialog: React.FC<ExportMarkdownDialogProps> = ({
|
||||
<code className='bg-base-300 rounded px-1'>annotation.note</code> -{' '}
|
||||
{_('Annotation note')}
|
||||
</li>
|
||||
<li className='ml-8'>
|
||||
<code className='bg-base-300 rounded px-1'>annotation.style</code> -{' '}
|
||||
{_('Annotation style')}: underline | highlight | squiggly
|
||||
</li>
|
||||
<li className='ml-8'>
|
||||
<code className='bg-base-300 rounded px-1'>annotation.color</code> -{' '}
|
||||
{_('Annotation color')}: yellow | red | green | blue | violet
|
||||
</li>
|
||||
<li className='ml-8'>
|
||||
<code className='bg-base-300 rounded px-1'>annotation.timestamp</code> -{' '}
|
||||
{_('Update time')}
|
||||
{_('Annotation time')}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
import nunjucks from 'nunjucks';
|
||||
|
||||
export type NoteTemplateData = {
|
||||
title: string;
|
||||
author: string;
|
||||
exportDate: number;
|
||||
chapters: {
|
||||
title: string;
|
||||
annotations: {
|
||||
text: string;
|
||||
note?: string;
|
||||
style?: string;
|
||||
color?: string;
|
||||
timestamp?: number;
|
||||
}[];
|
||||
}[];
|
||||
};
|
||||
|
||||
// Configure nunjucks environment
|
||||
const env = new nunjucks.Environment(null, {
|
||||
autoescape: false, // Don't auto-escape since we're generating markdown
|
||||
throwOnUndefined: false, // Return empty string for undefined variables
|
||||
trimBlocks: false, // Trim newlines after block tags
|
||||
lstripBlocks: true, // Strip leading whitespace before block tags
|
||||
});
|
||||
|
||||
// Add custom 'date' filter for Jinja2 compatibility
|
||||
// Supports Python strftime-style format strings
|
||||
env.addFilter('date', (value: number | string | undefined, format?: string) => {
|
||||
if (value === undefined || value === null) return '';
|
||||
|
||||
let date: Date;
|
||||
if (typeof value === 'number') {
|
||||
date = new Date(value);
|
||||
} else if (typeof value === 'string') {
|
||||
date = new Date(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (isNaN(date.getTime())) return '';
|
||||
|
||||
if (!format) {
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
// Convert Python strftime format to actual values
|
||||
return format
|
||||
.replace(/%Y/g, date.getFullYear().toString())
|
||||
.replace(/%m/g, String(date.getMonth() + 1).padStart(2, '0'))
|
||||
.replace(/%d/g, String(date.getDate()).padStart(2, '0'))
|
||||
.replace(/%H/g, String(date.getHours()).padStart(2, '0'))
|
||||
.replace(/%M/g, String(date.getMinutes()).padStart(2, '0'))
|
||||
.replace(/%S/g, String(date.getSeconds()).padStart(2, '0'))
|
||||
.replace(/%I/g, String(date.getHours() % 12 || 12).padStart(2, '0'))
|
||||
.replace(/%p/g, date.getHours() >= 12 ? 'PM' : 'AM')
|
||||
.replace(/%w/g, String(date.getDay()))
|
||||
.replace(/%j/g, getDayOfYear(date).toString().padStart(3, '0'))
|
||||
.replace(/%U/g, getWeekNumber(date).toString().padStart(2, '0'))
|
||||
.replace(/%W/g, getWeekNumber(date, true).toString().padStart(2, '0'))
|
||||
.replace(/%a/g, date.toLocaleDateString('en-US', { weekday: 'short' }))
|
||||
.replace(/%A/g, date.toLocaleDateString('en-US', { weekday: 'long' }))
|
||||
.replace(/%b/g, date.toLocaleDateString('en-US', { month: 'short' }))
|
||||
.replace(/%B/g, date.toLocaleDateString('en-US', { month: 'long' }))
|
||||
.replace(/%%/g, '%');
|
||||
});
|
||||
|
||||
// Helper to get day of year
|
||||
function getDayOfYear(date: Date): number {
|
||||
const start = new Date(date.getFullYear(), 0, 0);
|
||||
const diff = date.getTime() - start.getTime();
|
||||
const oneDay = 1000 * 60 * 60 * 24;
|
||||
return Math.floor(diff / oneDay);
|
||||
}
|
||||
|
||||
// Helper to get week number
|
||||
function getWeekNumber(date: Date, mondayFirst = false): number {
|
||||
const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
||||
const dayNum = mondayFirst ? d.getUTCDay() || 7 : d.getUTCDay();
|
||||
d.setUTCDate(d.getUTCDate() + 4 - dayNum);
|
||||
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
||||
return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
|
||||
}
|
||||
|
||||
// Add 'default' filter for providing fallback values
|
||||
env.addFilter('default', (value: unknown, defaultValue: unknown = '') => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
// Add 'truncate' filter
|
||||
env.addFilter('truncate', (value: string, length = 255, killwords = false, end = '...') => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
if (value.length <= length) return value;
|
||||
|
||||
if (killwords) {
|
||||
return value.slice(0, length) + end;
|
||||
}
|
||||
|
||||
// Find the last word boundary
|
||||
let truncated = value.slice(0, length);
|
||||
const lastSpace = truncated.lastIndexOf(' ');
|
||||
if (lastSpace > 0) {
|
||||
truncated = truncated.slice(0, lastSpace);
|
||||
}
|
||||
return truncated + end;
|
||||
});
|
||||
|
||||
// Add 'trim' filter
|
||||
env.addFilter('trim', (value: string) => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
return value.trim();
|
||||
});
|
||||
|
||||
// Add 'replace' filter
|
||||
env.addFilter('replace', (value: string, search: string, replacement: string) => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
return value.split(search).join(replacement);
|
||||
});
|
||||
|
||||
// Add 'upper' and 'lower' filters
|
||||
env.addFilter('upper', (value: string) => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
return value.toUpperCase();
|
||||
});
|
||||
|
||||
env.addFilter('lower', (value: string) => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
return value.toLowerCase();
|
||||
});
|
||||
|
||||
// Add 'capitalize' filter
|
||||
env.addFilter('capitalize', (value: string) => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
|
||||
});
|
||||
|
||||
// Add 'title' filter (capitalize each word)
|
||||
env.addFilter('title', (value: string) => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
return value.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase());
|
||||
});
|
||||
|
||||
// Add 'length' filter
|
||||
env.addFilter('length', (value: string | unknown[]) => {
|
||||
if (!value) return 0;
|
||||
return value.length;
|
||||
});
|
||||
|
||||
// Add 'first' and 'last' filters
|
||||
env.addFilter('first', (value: unknown[]) => {
|
||||
if (!Array.isArray(value) || value.length === 0) return undefined;
|
||||
return value[0];
|
||||
});
|
||||
|
||||
env.addFilter('last', (value: unknown[]) => {
|
||||
if (!Array.isArray(value) || value.length === 0) return undefined;
|
||||
return value[value.length - 1];
|
||||
});
|
||||
|
||||
// Add 'join' filter
|
||||
env.addFilter('join', (value: unknown[], separator = '') => {
|
||||
if (!Array.isArray(value)) return '';
|
||||
return value.join(separator);
|
||||
});
|
||||
|
||||
// Add 'nl2br' filter (convert newlines to <br>)
|
||||
env.addFilter('nl2br', (value: string) => {
|
||||
if (!value || typeof value !== 'string') return '';
|
||||
return value.replace(/\n/g, '<br>\n');
|
||||
});
|
||||
|
||||
/**
|
||||
* Renders a Jinja2/Nunjucks template with the given data
|
||||
* @param template The template string in Jinja2/Nunjucks syntax
|
||||
* @param data The data to render the template with
|
||||
* @returns The rendered template string
|
||||
*/
|
||||
export function renderNoteTemplate(template: string, data: NoteTemplateData): string {
|
||||
try {
|
||||
return env.renderString(template, data);
|
||||
} catch (error) {
|
||||
// Return error message in the output for debugging
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown template error';
|
||||
return `[Template Error: ${errorMessage}]\n\n${template}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a template string by attempting to compile it
|
||||
* @param template The template string to validate
|
||||
* @returns An object with isValid flag and optional error message
|
||||
*/
|
||||
export function validateNoteTemplate(template: string): { isValid: boolean; error?: string } {
|
||||
try {
|
||||
env.renderString(template, {
|
||||
title: '',
|
||||
author: '',
|
||||
exportDate: '',
|
||||
chapters: [],
|
||||
});
|
||||
return { isValid: true };
|
||||
} catch (error) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown template error',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nunjucks environment instance for advanced use cases
|
||||
*/
|
||||
export function getNunjucksEnv(): nunjucks.Environment {
|
||||
return env;
|
||||
}
|
||||
Generated
+45
@@ -266,6 +266,9 @@ importers:
|
||||
next:
|
||||
specifier: 16.0.10
|
||||
version: 16.0.10(@babel/core@7.28.6)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
nunjucks:
|
||||
specifier: ^3.2.4
|
||||
version: 3.2.4(chokidar@3.6.0)
|
||||
overlayscrollbars:
|
||||
specifier: ^2.11.4
|
||||
version: 2.13.0
|
||||
@@ -360,6 +363,9 @@ importers:
|
||||
'@types/node':
|
||||
specifier: ^22.15.31
|
||||
version: 22.19.7
|
||||
'@types/nunjucks':
|
||||
specifier: ^3.2.6
|
||||
version: 3.2.6
|
||||
'@types/react':
|
||||
specifier: ^19.0.0
|
||||
version: 19.2.9
|
||||
@@ -3661,6 +3667,9 @@ packages:
|
||||
'@types/node@22.19.7':
|
||||
resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==}
|
||||
|
||||
'@types/nunjucks@3.2.6':
|
||||
resolution: {integrity: sha512-pHiGtf83na1nCzliuAdq8GowYiXvH5l931xZ0YEHaLMNFgynpEqx+IPStlu7UaDkehfvl01e4x/9Tpwhy7Ue3w==}
|
||||
|
||||
'@types/phoenix@1.6.7':
|
||||
resolution: {integrity: sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==}
|
||||
|
||||
@@ -3974,6 +3983,9 @@ packages:
|
||||
resolution: {integrity: sha512-HZKJLFe4eGVgCe9J87PnijY7T1Zn638bEHS+Fm/ygHZozRpefzWcOYfPaP52S8pqk9g4xN3+LzMDl3Lv9dLglA==}
|
||||
engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=18.0.0'}
|
||||
|
||||
a-sync-waterfall@1.0.1:
|
||||
resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||
engines: {node: '>=6.5'}
|
||||
@@ -4168,6 +4180,9 @@ packages:
|
||||
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
asap@2.0.6:
|
||||
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
|
||||
|
||||
assertion-error@2.0.1:
|
||||
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -4429,6 +4444,10 @@ packages:
|
||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
commander@5.1.0:
|
||||
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
commander@7.2.0:
|
||||
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
|
||||
engines: {node: '>= 10'}
|
||||
@@ -6360,6 +6379,16 @@ packages:
|
||||
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
nunjucks@3.2.4:
|
||||
resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==}
|
||||
engines: {node: '>= 6.9.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
chokidar: ^3.3.0
|
||||
peerDependenciesMeta:
|
||||
chokidar:
|
||||
optional: true
|
||||
|
||||
nwsapi@2.2.23:
|
||||
resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==}
|
||||
|
||||
@@ -11967,6 +11996,8 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/nunjucks@3.2.6': {}
|
||||
|
||||
'@types/phoenix@1.6.7': {}
|
||||
|
||||
'@types/react-color@3.0.13(@types/react@19.2.9)':
|
||||
@@ -12301,6 +12332,8 @@ snapshots:
|
||||
|
||||
'@zip.js/zip.js@2.8.15': {}
|
||||
|
||||
a-sync-waterfall@1.0.1: {}
|
||||
|
||||
abort-controller@3.0.0:
|
||||
dependencies:
|
||||
event-target-shim: 5.0.1
|
||||
@@ -12516,6 +12549,8 @@ snapshots:
|
||||
get-intrinsic: 1.3.0
|
||||
is-array-buffer: 3.0.5
|
||||
|
||||
asap@2.0.6: {}
|
||||
|
||||
assertion-error@2.0.1: {}
|
||||
|
||||
assistant-cloud@0.1.13:
|
||||
@@ -12779,6 +12814,8 @@ snapshots:
|
||||
|
||||
commander@4.1.1: {}
|
||||
|
||||
commander@5.1.0: {}
|
||||
|
||||
commander@7.2.0: {}
|
||||
|
||||
commander@8.3.0: {}
|
||||
@@ -15281,6 +15318,14 @@ snapshots:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
|
||||
nunjucks@3.2.4(chokidar@3.6.0):
|
||||
dependencies:
|
||||
a-sync-waterfall: 1.0.1
|
||||
asap: 2.0.6
|
||||
commander: 5.1.0
|
||||
optionalDependencies:
|
||||
chokidar: 3.6.0
|
||||
|
||||
nwsapi@2.2.23: {}
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
Reference in New Issue
Block a user