Merge branch 'dev' into cmskit-page-rework

pull/17642/head
Enis Necipoglu 1 year ago
commit 60f6c3bd4f
No known key found for this signature in database
GPG Key ID: 1EC55E13241E1680

@ -493,6 +493,44 @@
"QuotationTemplate.Tax/VAT:": "Tax / Vat (%{0}) :",
"QuotationTemplate.TotalDiscount:": "Total Discount :",
"QuotationTemplate.TOTALDUE:": "TOTAL DUE :",
"QuotationTemplate.BankAccount": "Our bank account information can be found at {0}"
"QuotationTemplate.BankAccount": "Our bank account information can be found at {0}",
"Permission:Raffles": "Raffle",
"Permission:Draw": "Draw",
"Menu:Raffles": "Raffles",
"RaffleIsNotDrawable": "Raffle is not drawable",
"WinnerCountMustBeGreaterThanZero": "Winner count must be greater than zero",
"FullDescription": "Full Description",
"VisibilityStartDate": "Visibility Start Date",
"VisibilityEndDate": "Visibility End Date",
"RaffleDate": "Raffle Date",
"SubscriptionCode": "Subscription Code",
"GroupCode": "Group Code",
"MaxWinnerCount": "Max Winner Count",
"ReDraw": "Re-Draw",
"EditRaffle": "Edit Raffle",
"Raffles": "Raffles",
"CreateARaffle": "Create a raffle",
"Draw": "Draw",
"Enum:RaffleStatus:0": "Active",
"Enum:RaffleStatus:1": "Next",
"Enum:RaffleStatus:2": "Past",
"DrawDone": "Draw Done",
"HomePageShowType": "Home Page Show Type",
"None": "None",
"Card": "Card",
"Horizontal": "Horizontal",
"Winners": "Winners",
"StartDateMustBeLessThanEndDate": "Start date must be less than end date",
"VisibilityStartDateMustBeLessThanVisibilityEndDate": "Visibility start date must be less than visibility end date",
"StartDateMustBeGreaterThanVisibilityStartDate": "Start date must be greater than visibility start date",
"EndDateMustBeLessThanVisibilityEndDate": "End date must be less than visibility end date",
"DrawnDone": "Drawn Done",
"AddColor": "Add Color",
"Colors": "Colors",
"RemoveColor": "Remove Color",
"MaxColorCountWarning": "You can add up to {0} colors",
"MinColorCountWarning": "You must add at least {0} colors",
"RaffleDeletionConfirmationMessage": "Are you sure you want to delete this raffle?",
"CreateRaffle": "Create Raffle"
}
}

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\"> نظام أساسي كامل لتطوير الويب </ span> <span class=\"second-line\"> </ span> <span class=\"third-line\"> مدمج <img src=\"{0}\" width = \"110\" class=\"ml-1\" /> framework </span>",
"AbpCommercialShortDescription": "يوفر ABP Commercial وحدات تطبيق مسبقة الإنشاء وأدوات تطوير سريعة للتطبيقات وموضوعات واجهة مستخدم احترافية ودعمًا متميزًا والمزيد.",
"LiveDemo": "عرض حي",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> باستخدام حساب ABP الخاص بك، <a href=\"{2}\">{3}</a>إلى abp.io.<br/>أو املأ النموذج أدناه لإنشاء عرض توضيحي مباشر الآن",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "هناك حساب بالفعل باستخدام عنوان البريد الإلكتروني المحدد: <b>{0}</b><br/> يمكنك تسجيل الدخول باستخدام حسابك للمتابعة.",
"GetLicence": "احصل على ترخيص",
"Application": "تطبيق",
"StartupTemplates": "قوالب بدء تشغيل ABP",
@ -129,12 +131,14 @@
"YourFullName": "اسمك الكامل",
"EmailField": "عنوان البريد الإلكتروني",
"YourEmailAddress": "عنوان بريدك الإلكتروني",
"ValidEmailAddressIsRequired": "مطلوب عنوان بريد إلكتروني صالح.",
"HowMayWeHelpYou": "كيف يمكن أن نساعدك؟",
"SendMessage": "أرسل رسالة",
"Success": "النجاح",
"WeWillReplyYou": "لقد تلقينا رسالتك وسنتواصل معك قريبًا.",
"GoHome": "اذهب للمنزل",
"CreateLiveDemo": "إنشاء عرض حي",
"CreateLiveDemoDescription": "بمجرد إرسال هذا النموذج ، ستتلقى رسالة بريد إلكتروني تحتوي على رابط العرض التوضيحي الخاص بك.",
"RegisterToTheNewsletter": "سجل في النشرة الإخبارية لتلقي معلومات بخصوص ABP.IO ، بما في ذلك الإصدارات الجديدة وما إلى ذلك.",
"EnterYourEmailOrLogin": "أدخل عنوان بريدك الإلكتروني لإنشاء العرض التوضيحي أو <a href=\"{0}\"> تسجيل الدخول </a> باستخدام حسابك الحالي.",
"ApplicationTemplate": "نموذج التطبيق",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Kompletní</span><span class=\"second-line\"> platforma pro vývoj webu</span><span class=\"third-line\">vestavěná na <img src= \"{0}\" width=\"110\" class=\"ml-1\" /> framework</span>",
"AbpCommercialShortDescription": "ABP Commercial poskytuje předpřipravené aplikační moduly, nástroje pro rychlý vývoj aplikací, profesionální témata uživatelského rozhraní, prémiovou podporu a další.",
"LiveDemo": "Živá ukázka",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> pomocí vašeho účtu ABP, <a href=\"{2}\">{3}</a> na abp.io.<br/>Nebo vyplňte níže uvedený formulář a vytvořte si nyní živou ukázku",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Zadaná e-mailová adresa <b>{0}</b> je již registrována.<br/> Můžete se přihlásit se svým účtem a pokračovat.",
"GetLicence": "Získejte licenci",
"Application": "aplikace",
"StartupTemplates": "Spouštěcí šablony",
@ -129,12 +131,14 @@
"YourFullName": "Vaše celé jméno",
"EmailField": "Emailová adresa",
"YourEmailAddress": "Vaše emailová adresa",
"ValidEmailAddressIsRequired": "Je vyžadována platná e-mailová adresa.",
"HowMayWeHelpYou": "Jak vám můžeme pomoci?",
"SendMessage": "Poslat zprávu",
"Success": "Úspěch",
"WeWillReplyYou": "Obdrželi jsme vaši zprávu a brzy se vám ozveme.",
"GoHome": "Jdi domů",
"CreateLiveDemo": "Vytvořit živé demo",
"CreateLiveDemoDescription": "Po odeslání tohoto formuláře obdržíte e-mail obsahující odkaz na vaši ukázku.",
"RegisterToTheNewsletter": "Zaregistrujte se k odběru newsletteru a získejte informace o ABP.IO, včetně nových verzí atd.",
"EnterYourEmailOrLogin": "Chcete-li vytvořit ukázku, zadejte svou e-mailovou adresu nebo se <a href=\"{0}\">přihlaste</a> pomocí svého stávajícího účtu.",
"ApplicationTemplate": "Šablona aplikace",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Eine komplette</span><span class=\"second-line\"> Webentwicklungsplattform</span><span class=\"third-line\">aufgebaute <img src= \"{0}\" width=\"110\" class=\"ml-1\" /> Framework</span>",
"AbpCommercialShortDescription": "ABP Commercial bietet vorgefertigte Anwendungsmodule, schnelle Anwendungsentwicklungstools, professionelle UI-Themen, Premium-Support und mehr.",
"LiveDemo": "Live-Demo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> mit Ihrem ABP-Konto, <a href=\"{2}\">{3}</a> zu abp.io.<br/>Oder füllen Sie das Formular unten aus, um jetzt eine Live-Demo zu erstellen",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Es gibt bereits ein Konto mit der angegebenen E-Mail-Adresse: <b>{0}</b><br/> Sie können sich mit Ihrem Konto anmelden, um fortzufahren.",
"GetLicence": "Holen Sie sich eine Lizenz",
"Application": "Anwendung",
"StartupTemplates": "Startup-Vorlagen",
@ -129,12 +131,14 @@
"YourFullName": "Ihren vollständigen Namen",
"EmailField": "E-Mail-Addresse",
"YourEmailAddress": "Ihre E-Mail-Adresse",
"ValidEmailAddressIsRequired": "Eine gültige E-Mail-Adresse ist erforderlich.",
"HowMayWeHelpYou": "Wie können wir Ihnen helfen?",
"SendMessage": "Nachricht senden",
"Success": "Erfolg",
"WeWillReplyYou": "Wir haben Ihre Nachricht erhalten und werden uns in Kürze bei Ihnen melden.",
"GoHome": "Nach Hause gehen",
"CreateLiveDemo": "Live-Demo erstellen",
"CreateLiveDemoDescription": "Sobald Sie dieses Formular absenden, erhalten Sie eine E-Mail mit Ihrem Demo-Link.",
"RegisterToTheNewsletter": "Melden Sie sich für den Newsletter an, um Informationen zu ABP.IO, einschließlich Neuerscheinungen etc. zu erhalten.",
"EnterYourEmailOrLogin": "Geben Sie Ihre E-Mail-Adresse ein, um Ihre Demo zu erstellen, oder <a href=\"{0}\">Login</a> mit Ihrem bestehenden Konto.",
"ApplicationTemplate": "Bewerbungsvorlage",

@ -49,6 +49,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">A complete</span><span class=\"second-line\"> web development platform</span><span class=\"third-line\">built-on <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> framework</span>",
"AbpCommercialShortDescription": "ABP Commercial provides pre-built application modules, rapid application development tooling, professional UI themes, premium support and more.",
"LiveDemo": "Live Demo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> using your ABP account, <a href=\"{2}\">{3}</a> to abp.io.<br/>Or fill the form below to create a live demo now",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "There is already an account with the given email address: <b>{0}</b><br/> You can login with your account to proceed.",
"GetLicence": "Get a License",
"Application": "Application",
"StartupTemplates": "Startup Templates",
@ -132,12 +134,14 @@
"LastNameField": "Last Name",
"EmailField": "E-mail Address",
"YourEmailAddress": "Your e-mail address",
"ValidEmailAddressIsRequired": "A valid e-mail address is required.",
"HowMayWeHelpYou": "How may we help you?",
"SendMessage": "Send Message",
"Success": "Success",
"WeWillReplyYou": "We received your message and will be in touch shortly.",
"GoHome": "Go Home",
"CreateLiveDemo": "Create Live Demo",
"CreateLiveDemoDescription": "Once you submit this form, you will receive an email containing your demo link.",
"RegisterToTheNewsletter": "Register for the newsletter to receive information regarding ABP.IO, including new releases etc.",
"EnterYourEmailOrLogin": "Enter your e-mail address to create your demo or <a href=\"{0}\">Login</a> using your existing account.",
"ApplicationTemplate": "Application Template",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\"> Una </span> <span class=\"second-line\"> plataforma de desarrollo web completa </span> <span class=\"third-line\"> integrada <img src=\"{0}\" width = \"110\" class=\"ml-1\" /> marco </span>",
"AbpCommercialShortDescription": "ABP Commercial proporciona módulos de aplicaciones prediseñados, herramientas de desarrollo rápido de aplicaciones, temas de interfaz de usuario profesionales, soporte premium y más.",
"LiveDemo": "Demo en vivo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> usando su cuenta ABP, <a href=\"{2}\">{3}</a> a abp.io.<br/>O complete el siguiente formulario para crear una demostración en vivo ahora",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Ya existe una cuenta con la dirección de correo electrónico especificada: <b>{0}</b><br/> Puede iniciar sesión con su cuenta para continuar.",
"GetLicence": "Obtener una licencia",
"Application": "Solicitud",
"StartupTemplates": "Plantillas de inicio",
@ -129,12 +131,14 @@
"YourFullName": "Tu nombre completo",
"EmailField": "Dirección de correo electrónico",
"YourEmailAddress": "Tu correo electrónico",
"ValidEmailAddressIsRequired": "Se requiere una dirección de correo electrónico válida.",
"HowMayWeHelpYou": "¿Cómo podemos ayudarle?",
"SendMessage": "Enviar mensaje",
"Success": "Éxito",
"WeWillReplyYou": "Recibimos su mensaje y nos pondremos en contacto a la brevedad.",
"GoHome": "Vete a casa",
"CreateLiveDemo": "Crear demostración en vivo",
"CreateLiveDemoDescription": "Una vez que envíe este formulario, recibirá un correo electrónico con el enlace de su demostración.",
"RegisterToTheNewsletter": "Regístrese para recibir el boletín informativo para recibir información sobre ABP.IO, incluidos nuevos lanzamientos, etc.",
"EnterYourEmailOrLogin": "Ingrese su dirección de correo electrónico para crear su demostración o <a href=\"{0}\"> Iniciar sesión </a> con su cuenta existente.",
"ApplicationTemplate": "Plantilla de aplicación",

@ -49,6 +49,8 @@
"IndexPageHeroSection": "<span class=\"first-line\"> Täydellinen </span><span class=\"second-line\"> verkkokehitysympäristö </span><span class=\"third-line\"> sisäänrakennettu <img src=\"{0}\" width = \"110\" class=\"ml-1\" /> kehys </span>",
"AbpCommercialShortDescription": "ABP Commercial tarjoaa valmiita sovellusmoduuleja, nopean sovelluskehitystyökalun, ammattimaiset käyttöliittymäteemat, ensiluokkaisen tuen ja paljon muuta.",
"LiveDemo": "Live-esittely",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> käyttämällä ABP-tiliäsi, <a href=\"{2}\">{3}</a> abp.io: lle.<br/>Tai täytä alla oleva lomake luodaksesi live-esittelyn nyt",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Sähköpostiosoitteella <b>{0}</b> on jo tili.<br/> Voit kirjautua sisään tilillesi jatkaaksesi.",
"GetLicence": "Hanki lisenssi",
"Application": "Sovellus",
"StartupTemplates": "Käynnistysmallit",
@ -132,12 +134,14 @@
"LastNameField": "Sukunimi",
"EmailField": "Sähköpostiosoite",
"YourEmailAddress": "Sähköpostiosoitteesi",
"ValidEmailAddressIsRequired": "Kelvollinen sähköpostiosoite vaaditaan",
"HowMayWeHelpYou": "Kuinka voimme auttaa sinua?",
"SendMessage": "Lähetä viesti",
"Success": "Menestys",
"WeWillReplyYou": "Saimme viestisi ja otamme sinuun pian yhteyttä.",
"GoHome": "Mene kotiin",
"CreateLiveDemo": "Luo live-esittely",
"CreateLiveDemoDescription": "Kun lähetät tämän lomakkeen, saat sähköpostin, jossa on linkki demoosi.",
"RegisterToTheNewsletter": "Rekisteröidy uutiskirjeeseen saadaksesi tietoa ABP.IO: sta, mukaan lukien uudet julkaisut jne.",
"EnterYourEmailOrLogin": "Kirjoita sähköpostiosoitteesi luodaksesi esittely tai <a href=\"{0}\"> kirjaudu sisään </a> nykyisellä tililläsi.",
"ApplicationTemplate": "Sovelluksen malli",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Une plate-forme de développement Web</span><span class=\"second-line\"> complète </span><span class=\"third-line\"> intégrée <img src=\"{0}\" width = \"110\" class=\"ml-1\" /> cadre </span>",
"AbpCommercialShortDescription": "ABP Commercial fournit des modules d'application prédéfinis, des outils de développement rapide d'applications, des thèmes d'interface utilisateur professionnels, un support premium et plus encore.",
"LiveDemo": "Démo en direct",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> en utilisant votre compte ABP, <a href=\"{2}\">{3}</a> à abp.io.<br/>Ou remplissez le formulaire ci-dessous pour créer une démo en direct maintenant",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Il existe déjà un compte avec l'adresse e-mail fournie: <b>{0}</b><br/> Vous pouvez vous connecter avec votre compte pour continuer.",
"GetLicence": "Obtenez une licence",
"Application": "Application",
"StartupTemplates": "Modèles de démarrage",
@ -129,12 +131,14 @@
"YourFullName": "Votre nom complet",
"EmailField": "Adresse e-mail",
"YourEmailAddress": "Votre adresse email",
"ValidEmailAddressIsRequired": "Une adresse e-mail valide est requise.",
"HowMayWeHelpYou": "Comment pouvons nous vous aider?",
"SendMessage": "Envoyer le message",
"Success": "Succès",
"WeWillReplyYou": "Nous avons reçu votre message et vous contacterons sous peu.",
"GoHome": "Retour à l'acceuil",
"CreateLiveDemo": "Créer une démo en direct",
"CreateLiveDemoDescription": "Une fois que vous avez soumis ce formulaire, vous recevrez un e-mail contenant le lien de votre démo.",
"RegisterToTheNewsletter": "Inscrivez-vous à la newsletter pour recevoir des informations concernant ABP.IO, y compris les nouvelles versions, etc.",
"EnterYourEmailOrLogin": "Saisissez votre adresse e-mail pour créer votre démo ou <a href=\"{0}\"> Connectez-vous </a> à l'aide de votre compte existant.",
"ApplicationTemplate": "Modèle d'application",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">एक पूर्ण</span><span class=\"second-line\"> वेब डेवलपमेंट प्लेटफॉर्म</span><span class=\"third-line\">बिल्ट-ऑन <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> Framework</span>",
"AbpCommercialShortDescription": "एबीपी कमर्शियल प्री-बिल्ट एप्लिकेशन मॉड्यूल, रैपिड एप्लिकेशन डेवलपमेंट टूलिंग, पेशेवर यूआई थीम, प्रीमियम सपोर्ट आदि प्रदान करता है।",
"LiveDemo": "लाइव डेमो",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> अपने एबीपी खाते का उपयोग करते हुए, <a href=\"{2}\">{3}</a> abp.io पर आपका स्वागत है। <br/> या अब एक लाइव डेमो बनाने के लिए नीचे दिए गए फॉर्म को भरें",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "दिए गए ईमेल पते <b>{0}</b> के साथ पहले से ही एक खाता है। <br/> आप अपने खाते से लॉगिन करके आगे बढ़ सकते हैं।",
"GetLicence": "एक लाइसेंस प्राप्त करें",
"Application": "आवेदन",
"StartupTemplates": "स्टार्टअप टेम्पलेट",
@ -129,12 +131,14 @@
"YourFullName": "आपका पूरा नाम",
"EmailField": "ईमेल पता",
"YourEmailAddress": "आपका ईमेल पता",
"ValidEmailAddressIsRequired": "एक वैध ईमेल पता आवश्यक है।",
"HowMayWeHelpYou": "हम कैसे आपकी सहायता कर सकते हैं?",
"SendMessage": "मेसेज भेजें",
"Success": "सफलता",
"WeWillReplyYou": "हमें आपका संदेश प्राप्त हुआ और शीघ्र ही संपर्क में आएगा।",
"GoHome": "घर जाओ",
"CreateLiveDemo": "लाइव डेमो बनाएँ",
"CreateLiveDemoDescription": "एक बार जब आप इस फॉर्म को जमा करते हैं, तो आपको अपने डेमो लिंक को समेत एक ईमेल प्राप्त होगा।",
"RegisterToTheNewsletter": "ABP.IO के बारे में जानकारी प्राप्त करने के लिए न्यूज़लेटर के लिए रजिस्टर करें, जिसमें नई रिलीज़ आदि शामिल हैं।",
"EnterYourEmailOrLogin": "अपना डेमो बनाने के लिए अपना ई-मेल पता दर्ज करें या अपने मौजूदा खाते का उपयोग करके <a href=\"{0}\">लॉगिन करें</a>।",
"ApplicationTemplate": "एप्लिकेशन टेम्पलेट",

@ -49,6 +49,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Teljes</span><span class=\"second-line\"> webfejlesztői platform</span><span class=\"third-line\">beépített <img src= \"{0}\" width=\"110\" class=\"ml-1\" /> keretrendszer</span>",
"AbpCommercialShortDescription": "Az ABP Commercial előre beépített alkalmazásmodulokat, gyors alkalmazásfejlesztési eszközöket, professzionális felhasználói felületi témákat, prémium támogatást és még sok mást kínál.",
"LiveDemo": "Élő Demo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> az ABP-fiókjával, <a href=\"{2}\">{3}</a> az abp.io-ra.<br/>Vagy töltse ki az alábbi űrlapot, hogy most létrehozzon egy élő bemutatót",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Már van fiók a megadott e-mail címmel: <b>{0}</b><br/> Bejelentkezhet a fiókjával a folytatáshoz.",
"GetLicence": "Szerezzen engedélyt",
"Application": "Alkalmazás",
"StartupTemplates": "Indítási sablonok",
@ -132,12 +134,14 @@
"LastNameField": "Vezetéknév",
"EmailField": "Email cím",
"YourEmailAddress": "Az email címed",
"ValidEmailAddressIsRequired": "Érvényes e-mail cím szükséges",
"HowMayWeHelpYou": "Hogyan segíthetünk?",
"SendMessage": "Üzenet küldése",
"Success": "Siker",
"WeWillReplyYou": "Megkaptuk üzenetét, és hamarosan felvesszük Önnel a kapcsolatot.",
"GoHome": "Hazamenni",
"CreateLiveDemo": "Élő bemutató létrehozása",
"CreateLiveDemoDescription": "Miután elküldte ezt a űrlapot, e-mailt kap, amely tartalmazza a bemutató linkjét.",
"RegisterToTheNewsletter": "Regisztráljon a hírlevélre, hogy információkat kapjon az ABP.IO-ról, beleértve az új kiadásokat stb.",
"EnterYourEmailOrLogin": "Adja meg e-mail címét a bemutató létrehozásához, vagy <a href=\"{0}\">jelentkezzen be</a> meglévő fiókjával.",
"ApplicationTemplate": "Alkalmazássablon",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Heilstætt</span><span class=\"second-line\"> vefþróunar umhverfi </span><span class=\"third-line\">byggt á <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> ABP</span>",
"AbpCommercialShortDescription": "ABP Commercial býður upp á forsmíðaðar forritareiningar, tól sem hraða þróun, fagmanlega hannaðar UI þemur, úrvals stuðning og fleira.",
"LiveDemo": "Virkt sýnidæmi",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> með þínum ABP reikningi, <a href=\"{2}\">{3}</a> til abp.io.<br/>Eða fylltu út formið hér að neðan til að búa til virkt sýnidæmi núna",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Það er nú þegar reikningur með þessu netfangi: <b>{0}</b><br/> Þú getur skráð þig inn með þínum reikningi til að halda áfram.",
"GetLicence": "Sækja Leyfi",
"Application": "Umsókn",
"StartupTemplates": "Byrjunar Sniðmát",
@ -129,12 +131,14 @@
"YourFullName": "Þitt fulla nafn",
"EmailField": "Netfang",
"YourEmailAddress": "Netfangið þitt",
"ValidEmailAddressIsRequired": "Netfangið þarf að vera gilt.",
"HowMayWeHelpYou": "Hvernig getum við aðstoðað þig?",
"SendMessage": "Senda skilaboð",
"Success": "Heppnaðist",
"WeWillReplyYou": "Við höfum móttekið skilaboðin þín og munum hafa samband innan tíðar.",
"GoHome": "Fara heim",
"CreateLiveDemo": "Búa til Live Demo",
"CreateLiveDemoDescription": "Þegar þú sendir þetta form, færðu tölvupóst sem inniheldur tengilinn þinn.",
"RegisterToTheNewsletter": "Skráning á póstlista fyrir fréttabréf með upplýsingum um ABP.IO, þ.á.m. nýjar útgáfur o.s.frv..",
"EnterYourEmailOrLogin": "Settu inn netfangið þitt til að búa til kynningu eða <a href=\"{0}\">Login</a> með þínum notandareikningi.",
"ApplicationTemplate": "Forritssniðmát",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\"> Una completa </span><span class=\"second-line\"> piattaforma di sviluppo web </span><span class=\"third-line\"> integrata <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> framework </span>",
"AbpCommercialShortDescription": "ABP Commercial fornisce moduli applicativi predefiniti, strumenti per lo sviluppo rapido di applicazioni, temi dell'interfaccia utente professionale, supporto premium e altro ancora.",
"LiveDemo": "Dimostrazione dal vivo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> utilizzando il tuo account ABP, <a href=\"{2}\">{3}</a> a abp.io.<br/>O compilare il modulo sottostante per creare una demo live ora",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Esiste già un account con l'indirizzo email specificato: <b>{0}</b><br/> Puoi accedere con il tuo account per procedere.",
"GetLicence": "Ottieni una licenza",
"Application": "Applicazione",
"StartupTemplates": "Modelli di avvio",
@ -129,12 +131,14 @@
"YourFullName": "Il tuo nome completo",
"EmailField": "Indirizzo e-mail",
"YourEmailAddress": "Il tuo indirizzo di posta elettronica",
"ValidEmailAddressIsRequired": "È richiesto un indirizzo email valido.",
"HowMayWeHelpYou": "Come possiamo aiutarti?",
"SendMessage": "Invia messaggio",
"Success": "Successo",
"WeWillReplyYou": "Abbiamo ricevuto il tuo messaggio e ti contatteremo a breve.",
"GoHome": "Torna all'inizio",
"CreateLiveDemo": "Crea demo live",
"CreateLiveDemoDescription": "Una volta inviato questo modulo, riceverai un'e-mail contenente il link alla tua demo.",
"RegisterToTheNewsletter": "Registrati alla newsletter per ricevere informazioni su ABP.IO, comprese le nuove versioni ecc.",
"EnterYourEmailOrLogin": "Inserisci il tuo indirizzo e-mail per creare la tua demo o <a href=\"{0}\"> Accedi </a> utilizzando il tuo account esistente.",
"ApplicationTemplate": "Modello di applicazione",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Een compleet</span><span class=\"second-line\"> webontwikkelingsplatform</span><span class=\"third-line\">ingebouwd <img src= \"{0}\" width=\"110\" class=\"ml-1\" /> raamwerk</span>",
"AbpCommercialShortDescription": "ABP Commercial biedt kant-en-klare applicatiemodules, tooling voor snelle applicatieontwikkeling, professionele UI-thema's, premium ondersteuning en meer.",
"LiveDemo": "Live demonstratie",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> met behulp van uw ABP-account, <a href=\"{2}\">{3}</a> naar abp.io.<br/>Of vul het onderstaande formulier in om nu een live demo te maken",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Er is al een account met het opgegeven e-mailadres: <b>{0}</b><br/> U kunt inloggen met uw account om door te gaan.",
"GetLicence": "Verkrijg een licentie",
"Application": "Sollicitatie",
"StartupTemplates": "Opstartsjablonen",
@ -129,12 +131,14 @@
"YourFullName": "Je volledige naam",
"EmailField": "E-mailadres",
"YourEmailAddress": "Jouw e-mailadres",
"ValidEmailAddressIsRequired": "Een geldig e-mailadres is vereist.",
"HowMayWeHelpYou": "Hoe kunnen we je helpen?",
"SendMessage": "Bericht versturen",
"Success": "Succes",
"WeWillReplyYou": "We hebben uw bericht ontvangen en nemen spoedig contact met u op.",
"GoHome": "Ga naar huis",
"CreateLiveDemo": "Live demo maken",
"CreateLiveDemoDescription": "Zodra u dit formulier indient, ontvangt u een e-mail met uw demolink.",
"RegisterToTheNewsletter": "Schrijf je in voor de nieuwsbrief om informatie over ABP.IO te ontvangen, inclusief nieuwe releases etc.",
"EnterYourEmailOrLogin": "Voer uw e-mailadres in om uw demo te maken of <a href=\"{0}\">Log in</a> met uw bestaande account.",
"ApplicationTemplate": "Toepassingssjabloon",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">A complete</span><span class=\"second-line\"> web development platform</span><span class=\"third-line\">built-on <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> framework</span>",
"AbpCommercialShortDescription": "ABP Commercial zapewnia gotowe moduły aplikacji, narzędzia do szybkiego tworzenia aplikacji, profesjonalne motywy interfejsu użytkownika, wsparcie premium i nie tylko.",
"LiveDemo": "Demo na żywo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> korzystając z konta ABP, <a href=\"{2}\">{3}</a> to abp.io.<br/>Lub wypełnij poniższy formularz, aby utworzyć teraz demo na żywo",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Istnieje już konto o podanym adresie e-mail: <b>{0}</b><br/> Możesz się zalogować na swoje konto, aby kontynuować.",
"GetLicence": "Uzyskaj licencję",
"Application": "Podanie",
"StartupTemplates": "Szablony startowe",
@ -129,12 +131,14 @@
"YourFullName": "Twoje pełne imię",
"EmailField": "Adres e-mail",
"YourEmailAddress": "Twój adres email",
"ValidEmailAddressIsRequired": "Wymagany jest prawidłowy adres e-mail.",
"HowMayWeHelpYou": "Jak możemy Ci pomóc?",
"SendMessage": "Wyślij wiadomość",
"Success": "Powodzenie",
"WeWillReplyYou": "Otrzymaliśmy Twoją wiadomość i wkrótce się z Tobą skontaktujemy.",
"GoHome": "Idź do domu",
"CreateLiveDemo": "Utwórz demo na żywo",
"CreateLiveDemoDescription": "Po wysłaniu tego formularza otrzymasz e-mail z linkiem do swojego demo.",
"RegisterToTheNewsletter": "Zarejestruj się do newslettera, aby otrzymywać informacje dotyczące ABP.IO, w tym nowości itp.",
"EnterYourEmailOrLogin": "Wprowadź swój adres e-mail, aby utworzyć demo lub <a href=\"{0}\">Zaloguj się</a> przy użyciu istniejącego konta.",
"ApplicationTemplate": "Szablon aplikacji",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\"> Uma completa </span> <span class=\"second-line\"> plataforma de desenvolvimento web </span> <span class=\"third-line\"> integrada <img src=\"{0}\" width = \"110\" class=\"ml-1\" /> estrutura </span>",
"AbpCommercialShortDescription": "ABP Commercial fornece módulos de aplicativos pré-construídos, ferramentas de desenvolvimento rápido de aplicativos, temas de UI profissionais, suporte premium e muito mais.",
"LiveDemo": "Demonstração ao vivo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> usando sua conta ABP, <a href=\"{2}\">{3}</a> para abp.io.<br/>Ou preencha o formulário abaixo para criar uma demonstração ao vivo agora",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Já existe uma conta com o endereço de e-mail fornecido: <b>{0}</b><br/> Você pode fazer login com sua conta para continuar.",
"GetLicence": "Obtenha uma licença",
"Application": "Aplicativo",
"StartupTemplates": "Modelos de inicialização",
@ -129,12 +131,14 @@
"YourFullName": "Seu nome completo",
"EmailField": "Endereço de e-mail",
"YourEmailAddress": "Seu endereço de email",
"ValidEmailAddressIsRequired": "Um endereço de e-mail válido é obrigatório.",
"HowMayWeHelpYou": "Como podemos ajudá-lo?",
"SendMessage": "Enviar mensagem",
"Success": "Sucesso",
"WeWillReplyYou": "Recebemos sua mensagem e entraremos em contato em breve.",
"GoHome": "Ir para casa",
"CreateLiveDemo": "Criar demonstração ao vivo",
"CreateLiveDemoDescription": "Depois de enviar este formulário, você receberá um e-mail contendo o link da sua demonstração.",
"RegisterToTheNewsletter": "Cadastre-se no boletim informativo para receber informações sobre ABP.IO, incluindo novos lançamentos etc.",
"EnterYourEmailOrLogin": "Digite seu endereço de e-mail para criar sua demonstração ou <a href=\"{0}\"> Faça login </a> usando sua conta existente.",
"ApplicationTemplate": "Modelo de aplicativo",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">A complete</span><span class=\"second-line\"> web development platform</span><span class=\"third-line\">built-on <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> framework</span>",
"AbpCommercialShortDescription": "ABP Commercial oferă module de aplicaţii pre-construite, instrumente de dezvoltare rapidă a aplicaţiilor, teme UI profesionale, asistenţă premium şi multe altele.",
"LiveDemo": "Live Demo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> folosind contul ABP, <a href=\"{2}\">{3}</a> la abp.io.<br/>Sau completaţi formularul de mai jos pentru a crea un demo live acum",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Există deja un cont cu adresa de email specificată: <b>{0}</b><br/> Puteţi să vă autentificaţi cu contul dumneavoastră pentru a continua.",
"GetLicence": "Obţine o licenţă",
"Application": "Application",
"StartupTemplates": "Şabloane de lansare",
@ -129,12 +131,14 @@
"YourFullName": "Numele dumneavoastră complet",
"EmailField": "Adresa de email",
"YourEmailAddress": "Adresa dumneavoastră de email",
"ValidEmailAddressIsRequired": "Vă rugăm să introduceţi o adresă de email validă.",
"HowMayWeHelpYou": "Cum vă putem ajuta?",
"SendMessage": "Trimite mesaj",
"Success": "Succes",
"WeWillReplyYou": "Am primit mesajul dumneavoastră şi vă vom contacta cât de repede posibil.",
"GoHome": "Navigaţi acasă",
"CreateLiveDemo": "Crează Demo Live",
"CreateLiveDemoDescription": "După ce trimiteţi acest formular, veţi primi un email care conţine link-ul demo-ului dumneavoastră.",
"RegisterToTheNewsletter": "Înregistraţi-va la newsletter pentru a primi informaţii despre ABP.IO, inclusiv lansări noi etc.",
"EnterYourEmailOrLogin": "Introduceţi-vă adresa de email pentru a vă crea demo-ul sau <a href=\"{0}\">Autentificaţi-vă</a> folosind contul existent.",
"ApplicationTemplate": "Application Template",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\"> Полная </span> <span class=\"second-line\"> платформа веб-разработки </span> <span class=\"third-line\"> встроенная <img src=\"{0}\" width = \"110\" class=\"ml-1\" /> каркас </span>",
"AbpCommercialShortDescription": "ABP Commercial предоставляет готовые модули приложений, инструменты для быстрой разработки приложений, профессиональные темы пользовательского интерфейса, поддержку премиум-класса и многое другое.",
"LiveDemo": "Живая демонстрация",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> используя свою учетную запись ABP, <a href=\"{2}\">{3}</a> на abp.io. <br/> Или заполните форму ниже, чтобы создать живую демонстрацию прямо сейчас",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Уже есть учетная запись с указанным адресом электронной почты: <b>{0}</b><br/> Вы можете войти в свою учетную запись, чтобы продолжить.",
"GetLicence": "Получить лицензию",
"Application": "заявка",
"StartupTemplates": "Шаблоны запуска",
@ -129,12 +131,14 @@
"YourFullName": "Ваше полное имя",
"EmailField": "Адрес электронной почты",
"YourEmailAddress": "Ваш адрес электронной почты",
"ValidEmailAddressIsRequired": "Требуется действительный адрес электронной почты.",
"HowMayWeHelpYou": "Как мы можем Вам помочь?",
"SendMessage": "Отправить сообщение",
"Success": "Успех",
"WeWillReplyYou": "Мы получили ваше сообщение и скоро свяжемся с вами.",
"GoHome": "Иди домой",
"CreateLiveDemo": "Создать живую демонстрацию",
"CreateLiveDemoDescription": "После отправки этой формы вы получите электронное письмо со ссылкой на демонстрацию.",
"RegisterToTheNewsletter": "Подпишитесь на рассылку новостей, чтобы получать информацию о ABP.IO, в том числе о новых выпусках и т. Д.",
"EnterYourEmailOrLogin": "Введите свой адрес электронной почты, чтобы создать демоверсию, или <a href=\"{0}\"> войдите </a>, используя существующую учетную запись.",
"ApplicationTemplate": "Шаблон приложения",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Kompletná</span><span class=\"second-line\"> web vývojová platforma</span><span class=\"third-line\">postavená na <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> frameworku</span>",
"AbpCommercialShortDescription": "ABP Commercial poskytuje predpripravené aplikačné moduly, nástroje na rýchly vývoj aplikácií, profesionálne témy používateľského rozhrania, prémiovú podporu a ďalšie.",
"LiveDemo": "Live ukážka",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> použitím vášho ABP účtu, <a href=\"{2}\">{3}</a> na abp.io.<br/>Alebo vyplňte nižšie uvedený formulár a vytvorte si teraz live ukážku",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Už existuje účet s danou emailovou adresou: <b>{0}</b><br/> Môžete sa prihlásiť pomocou svojho účtu a pokračovať.",
"GetLicence": "Získajte licenciu",
"Application": "Aplikácia",
"StartupTemplates": "Štartovacie šablóny",
@ -129,12 +131,14 @@
"YourFullName": "Vaše celé meno",
"EmailField": "Emailová adresa",
"YourEmailAddress": "Vaša emailová adresa",
"ValidEmailAddressIsRequired": "Je potrebná platná emailová adresa.",
"HowMayWeHelpYou": "Ako vám môžeme pomôcť?",
"SendMessage": "Odoslať správu",
"Success": "Úspech",
"WeWillReplyYou": "Dostali sme vašu správu a čoskoro vás budeme kontaktovať.",
"GoHome": "Prejsť Domov",
"CreateLiveDemo": "Vytvoriť live ukážku",
"CreateLiveDemoDescription": "Po odoslaní tohto formulára obdržíte e-mail obsahujúci odkaz na vašu ukážku.",
"RegisterToTheNewsletter": "Zaregistrujte sa na odber noviniek a dostávajte informácie o ABP.IO, vrátane nových verzií atď.",
"EnterYourEmailOrLogin": "Zadajte svoju emailovú adresu a vytvorte si ukážku alebo sa <a href=\"{0}\">prihláste</a> pomocou svojho existujúceho konta.",
"ApplicationTemplate": "Šablóna žiadosti",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">Popolna</span><span class=\"second-line\"> platforma za spletno razvoj</span><span class=\"third-line\">vgrajena <img src= \"{0}\" width=\"110\" class=\"ml-1\" /> okvir</span>",
"AbpCommercialShortDescription": "ABP Commercial ponuja vnaprej izdelane aplikacijske module, orodja za hiter razvoj aplikacij, profesionalne teme uporabniškega vmesnika, vrhunsko podporo in še več.",
"LiveDemo": "Demo v živo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> s svojim ABP računom, <a href=\"{2}\">{3}</a> na abp.io.<br/>Ali izpolnite spodnji obrazec, da ustvarite demo v živo zdaj",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Za navedeni e-poštni naslov že obstaja račun: <b>{0}</b><br/> Lahko se prijavite s svojim računom, da nadaljujete.",
"GetLicence": "Pridobite licenco",
"Application": "Aplikacija",
"StartupTemplates": "Predloge za zagon",
@ -129,12 +131,14 @@
"YourFullName": "Tvoje polno ime",
"EmailField": "Email naslov",
"YourEmailAddress": "Vaš email naslov",
"ValidEmailAddressIsRequired": "Veljaven e-poštni naslov je obvezen",
"HowMayWeHelpYou": "Kako vam lahko pomagamo?",
"SendMessage": "Pošlji sporočilo",
"Success": "uspeh",
"WeWillReplyYou": "Prejeli smo vaše sporočilo in vas bomo v kratkem kontaktirali.",
"GoHome": "Pojdi domov",
"CreateLiveDemo": "Ustvari demo v živo",
"CreateLiveDemoDescription": "Ko pošljete ta obrazec, boste prejeli e-poštno sporočilo s povezavo do svojega demo.",
"RegisterToTheNewsletter": "Registrirajte se za glasilo, če želite prejemati informacije o ABP.IO, vključno z novimi izdajami itd.",
"EnterYourEmailOrLogin": "Vnesite svoj e-poštni naslov, če želite ustvariti predstavitev, ali <a href=\"{0}\">Prijavite se</a> z obstoječim računom.",
"ApplicationTemplate": "Predloga aplikacije",

@ -48,6 +48,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">A complete</span><span class=\"second-line\"> web development platform</span><span class=\"third-line\">built-on <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> framework</span>",
"AbpCommercialShortDescription": "ABP Commercial, önceden oluşturulmuş uygulama modülleri, hızlı uygulama geliştirme araçları, profesyonel UI temaları, premium destek ve daha fazlasını sağlar.",
"LiveDemo": "Canlı Demo",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> ABP hesabınızı kullanarak, <a href=\"{2}\">{3}</a> abp.io'ya hoş geldiniz.<br/>Veya aşağıdaki formu doldurarak şimdi canlı bir demo oluşturun",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Zaten <b>{0}</b> e-posta adresiyle bir hesap var.<br/> Devam etmek için hesabınızla giriş yapabilirsiniz.",
"GetLicence": "Lisans Alın",
"Application": "Başvuru",
"StartupTemplates": "Başlangıç Şablonları",
@ -131,12 +133,14 @@
"YourFullName": "Tam adınız",
"EmailField": "E-posta Adresi",
"YourEmailAddress": "E-posta adresiniz",
"ValidEmailAddressIsRequired": "Geçerli bir e-posta adresi gereklidir",
"HowMayWeHelpYou": "Size nasıl yardımcı olabiliriz?",
"SendMessage": "Mesaj gönder",
"Success": "Başarı",
"WeWillReplyYou": "Mesajınızı aldık ve kısa süre içinde sizinle iletişime geçeceğiz.",
"GoHome": "Eve git",
"CreateLiveDemo": "Canlı Demo Oluştur",
"CreateLiveDemoDescription": "Bu formu gönderdikten sonra, demo bağlantınızı içeren bir e-posta alacaksınız.",
"RegisterToTheNewsletter": "ABP.IO hakkında yeni yayınlar vb. dahil olmak üzere bilgi almak için haber bültenine kaydolun.",
"EnterYourEmailOrLogin": "Demonuzu oluşturmak için e-posta adresinizi girin veya mevcut hesabınızı kullanarak <a href=\"{0}\">Giriş yapın</a>.",
"ApplicationTemplate": "Uygulama Şablonu",

@ -46,6 +46,8 @@
"IndexPageHeroSection": "<span class=\"first-line\"> Nền tảng phát triển web hoàn chỉnh </span> <span class=\"second-line\"> </span> <span class=\"third-line\"> được tích hợp sẵn <img src=\"{0}\" width = \"110\" class=\"ml-1\" /> khung </span>",
"AbpCommercialShortDescription": "ABP Commercial cung cấp các mô-đun ứng dụng được tạo sẵn, công cụ phát triển ứng dụng nhanh chóng, các chủ đề giao diện người dùng chuyên nghiệp, hỗ trợ cao cấp và hơn thế nữa.",
"LiveDemo": "Bản thử trực tiếp",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> hoặc <a href=\"{2}\">{3}</a> đến abp.io. <br/> Hoặc điền vào biểu mẫu bên dưới để tạo bản trình diễn trực tiếp ngay bây giờ",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "Đã có một tài khoản với địa chỉ email đã cho: <b> {0} </b> <br/> Bạn có thể đăng nhập vào tài khoản của mình để tiếp tục.",
"GetLicence": "Nhận giấy phép",
"Application": "Ứng dụng",
"StartupTemplates": "Mẫu khởi động",
@ -129,12 +131,14 @@
"YourFullName": "Tên đầy đủ của bạn",
"EmailField": "Địa chỉ email",
"YourEmailAddress": "Địa chỉ email của bạn",
"ValidEmailAddressIsRequired": "Địa chỉ email hợp lệ là bắt buộc",
"HowMayWeHelpYou": "Chúng tôi có thể giúp gì cho bạn?",
"SendMessage": "Gửi tin nhắn",
"Success": "Sự thành công",
"WeWillReplyYou": "Chúng tôi đã nhận được tin nhắn của bạn và sẽ sớm liên hệ với bạn.",
"GoHome": "Về nhà",
"CreateLiveDemo": "Tạo bản trình diễn trực tiếp",
"CreateLiveDemoDescription": "Sau khi bạn gửi biểu mẫu này, bạn sẽ nhận được một email chứa liên kết bản demo của mình.",
"RegisterToTheNewsletter": "Đăng ký nhận bản tin để nhận thông tin về ABP.IO, bao gồm các bản phát hành mới, v.v.",
"EnterYourEmailOrLogin": "Nhập địa chỉ e-mail của bạn để tạo bản demo hoặc <a href=\"{0}\"> Đăng nhập </a> bằng tài khoản hiện có của bạn.",
"ApplicationTemplate": "Mẫu ứng dụng",

@ -49,6 +49,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">一个完整的</span><span class=\"second-line\">web开发平台</span><span class=\"third-line\">基于 <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> 框架</span>",
"AbpCommercialShortDescription": "ABP商业版提供了预构建的应用程序模块, 快速的应用程序开发工具, 专业的UI主题, 高级支持等.",
"LiveDemo": "在线演示",
"LiveDemoLead": "<a href=\"{0}\">{1}</a> 到你的ABP账户, <a href=\"{2}\">{3}</a> 到 abp.io.<br/>或者填写下面的表单立即创建在线演示",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "已经有一个使用此电子邮件地址的帐户: <b>{0}</b><br/> 你可以使用你的帐户登录继续.",
"GetLicence": "获得许可",
"Application": "应用程序",
"StartupTemplates": "启动模板",
@ -132,12 +134,14 @@
"LastNameField": "姓氏",
"EmailField": "E-mail地址",
"YourEmailAddress": "你的e-mail地址",
"ValidEmailAddressIsRequired": "请输入有效的e-mail地址",
"HowMayWeHelpYou": "需要获得购买帮助?(提供中文服务)",
"SendMessage": "发送消息",
"Success": "成功",
"WeWillReplyYou": "你的消息已经发送! 我们会在短时间内给你答复.",
"GoHome": "回到主页面",
"CreateLiveDemo": "创建在线演示",
"CreateLiveDemoDescription": "一旦你提交此表单,你将收到一封包含你的演示链接的电子邮件.",
"RegisterToTheNewsletter": "注册到时事简报以获取有关ABP.IO的消息,比如新发布的内容.",
"EnterYourEmailOrLogin": "输入你的e-mail地址来创建你的演示或者使用你的已有账号<a href=\"{0}\">登录</a>.",
"ApplicationTemplate": "应用程序模板",

@ -48,6 +48,8 @@
"IndexPageHeroSection": "<span class=\"first-line\">一個完整的</span><span class=\"second-line\">web開發平臺</span><span class=\"third-line\">基於 <img src=\"{0}\" width=\"110\" class=\"ml-1\" /> 框架</span>",
"AbpCommercialShortDescription": "ABP商業版提供了預構建的應用程序模塊, 快速的應用程序開發工具, 專業的UI主題, 高級支持等.",
"LiveDemo": "在線演示",
"LiveDemoLead": " <a href=\"{0}\">{1}</a> 使用你的ABP賬號, <a href=\"{2}\">{3}</a> 到 abp.io.<br/>或者填寫下面的表單立即創建一個在線演示",
"ThereIsAlreadyAnAccountWithTheGivenEmailAddress": "已經有一個使用該電子郵件地址的賬號: <b>{0}</b><br/> 你可以使用你的賬號登錄以繼續.",
"GetLicence": "獲得許可",
"Application": "應用程序",
"StartupTemplates": "啟動模板",
@ -131,12 +133,14 @@
"YourFullName": "你的全名",
"EmailField": "E-mail地址",
"YourEmailAddress": "你的e-mail地址",
"ValidEmailAddressIsRequired": "請輸入有效的e-mail地址",
"HowMayWeHelpYou": "我們如何幫助你",
"SendMessage": "發送消息",
"Success": "成功",
"WeWillReplyYou": "你的消息已經發送! 我們會在短時間內給你答復.",
"GoHome": "回到主頁面",
"CreateLiveDemo": "創建在線演示",
"CreateLiveDemoDescription": "一旦你提交此表單,你將收到一封包含你的演示鏈接的電子郵件.",
"RegisterToTheNewsletter": "註冊到時事簡報以獲取有關ABP.IO的消息,比如新發布的內容.",
"EnterYourEmailOrLogin": "輸入你的e-mail地址來創建你的演示或者使用你的已有賬號<a href=\"{0}\">登錄</a>.",
"ApplicationTemplate": "應用程序模板",

@ -191,6 +191,34 @@
"DiscordPageTitle": "ABP Discord Community",
"ViewVideo": "View Video",
"AbpCommunityTitleContent": "ABP Community - Open Source ABP Framework",
"CommunitySlogan": "A unique community platform for <span class=\"d-inline-block d-md-block gradient-community\">ABP Lovers</span>"
"CommunitySlogan": "A unique community platform for <span class=\"d-inline-block d-md-block gradient-community\">ABP Lovers</span>",
"RaffleIsNotActive": "Raffle is not active",
"YouAreAlreadyJoinedToThisRaffle": "You are already joined to this raffle",
"InvalidSubscriptionCode": "Invalid subscription code",
"Raffle:{0}": "Raffle: {0}",
"Join": "Join",
"Leave": "Leave",
"LoginToJoin": "Login to join",
"ToEnd:": "To end:",
"ToStart:": "To start:",
"days": "days",
"hrs": "hrs",
"min": "min",
"sec": "sec",
"Winners:": "Winners:",
"To{0}LuckyWinners": "to {0} lucky winner(s)",
"ActiveRaffles": "Active <span class=\"gradient-community\">Raffles</span>",
"UpcomingRaffles": "Upcoming <span class=\"gradient-community\">Raffles</span>",
"CompletedRaffles": "Completed <span class=\"gradient-community\">Raffles</span>",
"NoActiveRaffleTitle": "No active raffle is available at the moment.",
"NoActiveRaffleDescription": "No active raffle is available at the moment.",
"RaffleSubscriptionCodeInputMessage": "This raffle requires a registration code. Please enter the registration code below:",
"RaffleSubscriptionCodeInputErrorMessage": "The registration code is incorrect. Please try again.",
"GoodJob!": "Good Job!",
"RaffleJoinSuccessMessage": "You are successfully registered tor the raffle. You will be informed via email if you win the prize!",
"RaffleLoginAndRegisterMessage": "You should sign in to join a raffle. You can create an account for free if you haven't registered yet.",
"Ok": "Ok",
"SeeDetails": "See Details",
"WaitingForDraw": "Waiting for draw"
}
}

@ -3,6 +3,7 @@
"texts": {
"Buy": "Buy",
"SeeBookDetails": "See Book Details",
"MasteringAbpFrameworkEBookDescription": "This book will help you gain a complete understanding of the framework and modern web application development techniques."
"MasteringAbpFrameworkEBookDescription": "This book will help you gain a complete understanding of the framework and modern web application development techniques.",
"Feedback": "Feedback"
}
}

@ -0,0 +1,236 @@
# Moving Background Job Execution To A Separate Application
In this article, I will show you how to move the background job execution to a separate application.
Here are some benefits of doing this:
* If your background jobs consume high system resources (CPU, RAM or Disk), then you can deploy that background application to a dedicated server so it won't affect your application's performance.
* You can scale your background job application independently from your web application. For example, you can deploy multiple instances of your background job application to a Kubernetes cluster and scale it easily.
Here are some disadvantages of doing this:
* You need to deploy and maintain at least two applications instead of one.
* You need to implement a mechanism to share the common code between your applications. For example, you can create a shared project and add it to your applications as a project reference.
## Source code
You can find the source code of the application at [abpframework/abp-samples](https://github.com/abpframework/abp-samples/tree/master/SeparateBackgroundJob).
You can check the PR to see the changes step by step: [abpframework/abp-samples#250](https://github.com/abpframework/abp-samples/pull/250)
## Creating the Web Application
First, we need to create a new web application using the ABP CLI:
```bash
abp new SeparateBackgroundJob -t app
```
* Create a shared project named `SeparateBackgroundJob.Common.Shared` to share the `BackgroundJob` and `BackgroundJobArgs` classes between the web and job executor applications.
* Install the `Volo.Abp.BackgroundJobs.Abstractions` package to the `SeparateBackgroundJob.Common.Shared` project.
Add the `SeparateBackgroundJobCommonSharedModule` class to the `SeparateBackgroundJob.Common.Shared` project:
```csharp
[DependsOn(typeof(AbpBackgroundJobsAbstractionsModule))]
public class SeparateBackgroundJobCommonSharedModule : AbpModule
{
}
```
Add the `MyReportJob` and `MyReportJobArgs` classes to the `SeparateBackgroundJob.Common.Shared` project:
```csharp
public class MyReportJob : AsyncBackgroundJob<MyReportJobArgs>, ITransientDependency
{
public override Task ExecuteAsync(MyReportJobArgs args)
{
Logger.LogInformation("Executing MyReportJob with args: {0}", args.Content);
return Task.CompletedTask;
}
}
public class MyReportJobArgs
{
public string? Content { get; set; }
}
```
Add the `SeparateBackgroundJob.Common.Shared` project reference to the `SeparateBackgroundJob.Domain` project and add `SeparateBackgroundJobCommonSharedModule` to the `DependsOn` attribute of the `SeparateBackgroundJobDomainModule` class:
```csharp
[DependsOn(
typeof(SeparateBackgroundJobDomainSharedModule),
typeof(AbpAuditLoggingDomainModule),
typeof(AbpBackgroundJobsDomainModule),
typeof(AbpFeatureManagementDomainModule),
typeof(AbpIdentityDomainModule),
typeof(AbpOpenIddictDomainModule),
typeof(AbpPermissionManagementDomainOpenIddictModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(AbpSettingManagementDomainModule),
typeof(AbpTenantManagementDomainModule),
typeof(AbpEmailingModule),
typeof(SeparateBackgroundJobCommonSharedModule) //Add this line
)]
public class SeparateBackgroundJobDomainModule : AbpModule
```
Open the `Index.cshtml` and replace the content with the following code:
```csharp
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using SeparateBackgroundJob.Localization
@using Volo.Abp.Users
@model SeparateBackgroundJob.Web.Pages.IndexModel
@inject IHtmlLocalizer<SeparateBackgroundJobResource> L
@inject ICurrentUser CurrentUser
@section styles {
<abp-style src="/Pages/Index.css"/>
}
@section scripts {
<abp-script src="/Pages/Index.js"/>
}
<div class="container">
<abp-card>
<abp-card-header>
<abp-card-title>
Add NEW BACKGROUND JOB
</abp-card-title>
</abp-card-header>
<abp-card-body>
<form id="NewItemForm" method="post" class="row row-cols-lg-auto g-3 align-items-center">
<div class="col-12">
<div class="input-group">
<input id="ReportContent" required name="ReportContent" type="text" class="form-control" placeholder="enter text...">
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Add</button>
</div>
</form>
</abp-card-body>
</abp-card>
</div>
```
Open the `Index.cshtml.cs` and replace the content with the following code:
```csharp
public class IndexModel : SeparateBackgroundJobPageModel
{
private readonly IBackgroundJobManager _backgroundJobManager;
[BindProperty(SupportsGet = true)]
public string? ReportContent { get; set; }
public IndexModel(IBackgroundJobManager backgroundJobManager)
{
_backgroundJobManager = backgroundJobManager;
}
public void OnGet()
{
}
public async Task OnPostAsync()
{
await _backgroundJobManager.EnqueueAsync(new MyReportJobArgs
{
Content = ReportContent
});
Alerts.Success("Job is queued!");
}
}
```
Run the application and navigate to the home page. You should see the following page:
![1](images/1.png)
When you enter some text and click the **Add** button, the job will be queued and executed in the web application:
## Creating the Console Application
Now we split the background job execution to a separate console application.
Open the `SeparateBackgroundJobWebModule` class to disable the background job execution in the web application:
```csharp
public class SeparateBackgroundJobWebModule : AbpModule
{
....
public override void ConfigureServices(ServiceConfigurationContext context)
{
...
//Disable background job execution in the web application
Configure<AbpBackgroundJobOptions>(options =>
{
options.IsJobExecutionEnabled = false;
});
}
...
}
```
* Create a new console application using the ABP CLI:
```bash
abp new BackgroundJobExecutor -t console
```
* Add the `BackgroundJobExecutor` project to the solution of the web application.
* Add the `SeparateBackgroundJob.Common.Shared` project reference to the `BackgroundJobExecutor` project.
* Install the `Volo.Abp.BackgroundJobs.EntityFrameworkCore` and `Volo.Abp.EntityFrameworkCore.SqlServer` packages to the `BackgroundJobExecutor` project.
Update the `BackgroundJobExecutorModule` class as follows:
```csharp
[DependsOn(
typeof(AbpAutofacModule),
typeof(AbpBackgroundJobsEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqlServerModule),
typeof(SeparateBackgroundJobCommonSharedModule)
)]
public class BackgroundJobExecutorModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer();
});
}
....
}
```
Open the `appsettings.json` file to configure the [connection string](https://docs.abp.io/en/abp/latest/Connection-Strings#configure-the-connection-strings):
```json
{
"ConnectionStrings": {
"AbpBackgroundJobs": "Server=(LocalDb)\\MSSQLLocalDB;Database=SeparateBackgroundJob;Trusted_Connection=True"
}
}
```
> You must use the same connection string for the web application, `AbpBackgroundJobs` is the default connection string name for the background job module.
The solution structure should look like this:
![solution](images/solution.png)
Now, run the web and console application. When you enter some text and click the **Add** button, the job will be queued and executed in the console application:
![2](images/2.png)

@ -0,0 +1,12 @@
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Zxcvbn;
public class ZxcvbnScriptContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/zxcvbn/zxcvbn.js");
}
}

@ -42,6 +42,7 @@ public abstract class AbpAspNetCoreIntegratedTestBase<TStartupModule> : AbpTestB
protected virtual IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.AddAppSettingsSecretsJson()
.ConfigureWebHostDefaults(webBuilder =>
{
if (typeof(TStartupModule).IsAssignableTo<IAbpModule>())

@ -27,7 +27,9 @@ public abstract class AbpWebApplicationFactoryIntegratedTest<TProgram> : WebAppl
protected override IHost CreateHost(IHostBuilder builder)
{
builder.ConfigureServices(ConfigureServices);
builder
.AddAppSettingsSecretsJson()
.ConfigureServices(ConfigureServices);
return base.CreateHost(builder);
}

@ -23,6 +23,7 @@
<PackageReference Include="Polly" Version="$(PollyPackageVersion)" />
<PackageReference Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageReference Include="LibGit2Sharp" Version="0.26.2" />
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
</ItemGroup>
<ItemGroup>

@ -8,12 +8,14 @@ using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using StackExchange.Redis;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Bundling;
using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.LIbs;
using Volo.Abp.Cli.ProjectBuilding;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectBuilding.Templates.App;
using Volo.Abp.Cli.ProjectModification;
using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
@ -89,6 +91,8 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien
var projectArgs = await GetProjectBuildArgsAsync(commandLineArgs, template, projectName);
await CheckCreatingRequirements(projectArgs);
var result = await TemplateProjectBuilder.BuildAsync(
projectArgs
);
@ -97,6 +101,8 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien
Logger.LogInformation($"'{projectName}' has been successfully created to '{projectArgs.OutputFolder}'");
await CheckCreatedRequirements(projectArgs);
ConfigureNpmPackagesForTheme(projectArgs);
await CreateOpenIddictPfxFilesAsync(projectArgs);
await RunGraphBuildForMicroserviceServiceTemplate(projectArgs);
@ -120,6 +126,46 @@ public class NewCommand : ProjectCreationCommandBase, IConsoleCommand, ITransien
OpenRelatedWebPage(projectArgs, template, isTiered, commandLineArgs);
}
private Task CheckCreatingRequirements(ProjectBuildArgs projectArgs)
{
return Task.CompletedTask;
}
private async Task CheckCreatedRequirements(ProjectBuildArgs projectArgs)
{
var errors = new List<string>();
if (projectArgs.ExtraProperties.ContainsKey("PreRequirements:Redis"))
{
var isConnected = false;
try
{
var redis = await ConnectionMultiplexer.ConnectAsync("127.0.0.1", options => options.ConnectTimeout = 3000);
isConnected = redis.IsConnected;
}
catch (Exception e)
{
// ignored
}
finally
{
if (!isConnected)
{
errors.Add("\t* Redis is not installed or not running on your computer.");
}
}
}
if (errors.Any())
{
Logger.LogWarning("NOTICE: The following tools are required to run your solution.");
foreach (var error in errors)
{
Logger.LogWarning(error);
}
}
}
public string GetUsageInfo()
{
var sb = new StringBuilder();

@ -484,6 +484,11 @@ public abstract class ProjectCreationCommandBase
protected Task CreateOpenIddictPfxFilesAsync(ProjectBuildArgs projectArgs)
{
if (!projectArgs.ExtraProperties.ContainsKey(nameof(RandomizeAuthServerPassPhraseStep)))
{
return Task.CompletedTask;
}
var module = projectArgs.ExtraProperties[nameof(RandomizeAuthServerPassPhraseStep)];
if (string.IsNullOrWhiteSpace(module))
{

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Cli.ProjectBuilding.Templates;
namespace Volo.Abp.Cli.ProjectBuilding.Building;
@ -28,7 +29,14 @@ public abstract class TemplateInfo
public virtual IEnumerable<ProjectBuildPipelineStep> GetCustomSteps(ProjectBuildContext context)
{
return Array.Empty<ProjectBuildPipelineStep>();
var steps = new List<ProjectBuildPipelineStep>();
ConfigureCheckPreRequirements(context, steps);
return steps;
}
protected void ConfigureCheckPreRequirements(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
steps.Add(new CheckRedisPreRequirements());
}
public bool IsPro()

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectBuilding.Building.Steps;
@ -20,7 +21,7 @@ public abstract class AppNoLayersTemplateBase : AppTemplateBase
public override IEnumerable<ProjectBuildPipelineStep> GetCustomSteps(ProjectBuildContext context)
{
var steps = new List<ProjectBuildPipelineStep>();
var steps = base.GetCustomSteps(context).ToList();
switch (context.BuildArgs.DatabaseProvider)
{

@ -28,7 +28,7 @@ public abstract class AppTemplateBase : TemplateInfo
public override IEnumerable<ProjectBuildPipelineStep> GetCustomSteps(ProjectBuildContext context)
{
var steps = new List<ProjectBuildPipelineStep>();
var steps = base.GetCustomSteps(context).ToList();
ConfigureTenantSchema(context, steps);
SwitchDatabaseProvider(context, steps);
@ -165,7 +165,11 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveFolderStep("/angular"));
}
if (context.BuildArgs.MobileApp != MobileApp.ReactNative)
if(context.BuildArgs.MobileApp == MobileApp.ReactNative)
{
context.Symbols.Add("mobile:react-native");
}
else
{
steps.Add(new RemoveFolderStep(MobileApp.ReactNative.GetFolderName().EnsureStartsWith('/')));
}
@ -174,6 +178,7 @@ public abstract class AppTemplateBase : TemplateInfo
{
steps.Add(new MauiChangeApplicationIdGuidStep());
steps.Add(new MauiChangePortStep());
context.Symbols.Add("mobile:maui");
}
else
{
@ -192,10 +197,12 @@ public abstract class AppTemplateBase : TemplateInfo
context.BuildArgs.ExtraProperties.ContainsKey("separate-auth-server"))
{
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Public"));
context.Symbols.Add("ui:mvc-public-host");
}
else
{
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Public.Host"));
context.Symbols.Add("ui:mvc-public");
}
}
}
@ -399,6 +406,7 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.HttpApi.Host"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
}
@ -424,6 +432,7 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.IdentityServer"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
@ -517,6 +526,7 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.IdentityServer"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
@ -554,6 +564,7 @@ public abstract class AppTemplateBase : TemplateInfo
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.IdentityServer"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.AuthServer"));
steps.Add(new TemplateProjectRenameStep("MyCompanyName.MyProjectName.HttpApi.HostWithIds", "MyCompanyName.MyProjectName.HttpApi.Host"));
context.Symbols.Add("HostWithIds");
steps.Add(new AppTemplateChangeConsoleTestClientPortSettingsStep("44305"));
}
}

@ -0,0 +1,17 @@
using System;
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Building;
namespace Volo.Abp.Cli.ProjectBuilding.Templates;
public class CheckRedisPreRequirements : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
var modules = context.Files.Where(f => f.Name.EndsWith("Module.cs", StringComparison.OrdinalIgnoreCase));
if (modules.Any(module => module.Content.Contains("Redis:Configuration")))
{
context.BuildArgs.ExtraProperties["PreRequirements:Redis"] = "true";
}
}
}

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectBuilding.Building.Steps;
@ -33,14 +34,14 @@ public abstract class MicroserviceServiceTemplateBase : TemplateInfo
public override IEnumerable<ProjectBuildPipelineStep> GetCustomSteps(ProjectBuildContext context)
{
var steps = new List<ProjectBuildPipelineStep>();
var steps = base.GetCustomSteps(context).ToList();
DeleteUnrelatedUiProject(context, steps);
SetRandomPortForHostProject(context, steps);
RandomizeStringEncryption(context, steps);
RandomizeAuthServerPassPhrase(context, steps);
ChangeConnectionString(context, steps);
return steps;
}

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectBuilding.Building.Steps;
@ -19,7 +20,7 @@ public abstract class MicroserviceTemplateBase : TemplateInfo
public override IEnumerable<ProjectBuildPipelineStep> GetCustomSteps(ProjectBuildContext context)
{
var steps = new List<ProjectBuildPipelineStep>();
var steps = base.GetCustomSteps(context).ToList();
DeleteUnrelatedProjects(context, steps);
RandomizeStringEncryption(context, steps);

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectBuilding.Building.Steps;
@ -21,7 +22,7 @@ public abstract class ModuleTemplateBase : TemplateInfo
public override IEnumerable<ProjectBuildPipelineStep> GetCustomSteps(ProjectBuildContext context)
{
var steps = new List<ProjectBuildPipelineStep>();
var steps = base.GetCustomSteps(context).ToList();
DeleteUnrelatedProjects(context, steps);
RandomizeSslPorts(context, steps);

@ -18,11 +18,12 @@ public static class ConfigurationHelper
var builder = new ConfigurationBuilder()
.SetBasePath(options.BasePath!)
.AddJsonFile(options.FileName + ".json", optional: options.Optional, reloadOnChange: options.ReloadOnChange);
.AddJsonFile(options.FileName + ".json", optional: options.Optional, reloadOnChange: options.ReloadOnChange)
.AddJsonFile(options.FileName + ".secrets.json", optional: true, reloadOnChange: options.ReloadOnChange);
if (!options.EnvironmentName.IsNullOrEmpty())
{
builder = builder.AddJsonFile($"{options.FileName}.{options.EnvironmentName}.json", optional: options.Optional, reloadOnChange: options.ReloadOnChange);
builder = builder.AddJsonFile($"{options.FileName}.{options.EnvironmentName}.json", optional: true, reloadOnChange: options.ReloadOnChange);
}
if (options.EnvironmentName == "Development")

@ -24,6 +24,7 @@ public class AbpFluentValidationConventionalRegistrar : DefaultConventionalRegis
{
return new List<Type>()
{
type,
typeof(IValidator<>).MakeGenericType(GetFirstGenericArgumentOrNull(type, 1)!)
};
}

@ -114,7 +114,21 @@ public class JQueryProxyScriptGenerator : IProxyScriptGenerator, ITransientDepen
if (versionParam != null)
{
var version = FindBestApiVersion(action);
script.AppendLine($" var {ProxyScriptingJsFuncHelper.NormalizeJsVariableName(versionParam.Name)} = api_version ? api_version : '{version}';");
if (parameterList.Contains("api_version"))
{
script.AppendLine($" var {ProxyScriptingJsFuncHelper.NormalizeJsVariableName(versionParam.Name)} = api_version ? api_version : '{version}';");
}
else
{
var apiVersion = action.Parameters.FirstOrDefault(p =>
p.BindingSourceId.IsIn(ParameterBindingSources.ModelBinding, ParameterBindingSources.Query) &&
p.Name == "api-version");
if (apiVersion != null && parameterList.Contains(apiVersion.NameOnMethod))
{
var apiVersionVariable = ProxyScriptingJsFuncHelper.GetParamNameInJsFunc(apiVersion);
script.AppendLine($" {apiVersionVariable} = {apiVersionVariable} ? {apiVersionVariable} : '{version}';");
}
}
}
script.AppendLine(" return abp.ajax($.extend(true, {");

@ -103,6 +103,17 @@ public class ApplicationService_FluentValidation_Tests : AbpIntegratedTest<Appli
output.ShouldBe("444");
}
[Fact]
public void Should_Add_Validators_To_DI()
{
var validator = ServiceProvider.GetService<IValidator<MyMethodInput>>();
validator.GetType().ShouldBe(typeof(MyMethodInputValidator));
validator = ServiceProvider.GetService<MyMethodInputValidator>();
validator.GetType().ShouldBe(typeof(MyMethodInputValidator));
}
[DependsOn(typeof(AbpAutofacModule))]
[DependsOn(typeof(AbpFluentValidationModule))]
public class TestModule : AbpModule

@ -253,12 +253,13 @@ $(function () {
initEditor();
var editor;
var addWidgetButton;
function initEditor() {
var $editorContainer = $("#ContentEditor");
var inputName = $editorContainer.data('input-id');
var $editorInput = $('#' + inputName);
var initialValue = $editorInput.val();
addWidgetButton = createAddWidgetButton();
editor = new toastui.Editor({
el: $editorContainer[0],
@ -279,7 +280,7 @@ $(function () {
['code', 'codeblock'],
// Using Option: Customize the last button
[{
el: createAddWidgetButton(),
el: addWidgetButton,
command: 'bold',
tooltip: 'Add Widget'
}]
@ -334,20 +335,28 @@ $(function () {
editor.insertText(txt);
});
var $previewArea;
$('.tab-item').on('click', function () {
if ($(this).attr("aria-label") == 'Preview' && editor.isMarkdownMode()) {
if(!$previewArea){
$previewArea = $("#ContentEditor .toastui-editor-md-preview");
$previewArea.replaceWith("<iframe id='previewArea' style='height: 100%; width: 100%; border: 0px; display: inline;'></iframe>");
}
$previewArea.attr("srcdoc", '');
addWidgetButton.disabled = true;
let content = editor.getMarkdown();
localStorage.setItem('content', content);
$.post("/CmsKitCommonWidgets/ContentPreview", { content: content }, function (result) {
editor.setHTML(result);
var highllightedText = $('#ContentEditor').find('.toastui-editor-md-preview-highlight');
highllightedText.removeClass('toastui-editor-md-preview-highlight');
$previewArea = $("#previewArea");
$previewArea.attr("srcdoc", result);
});
}
else if ($(this).attr("aria-label") == 'Write') {
addWidgetButton.disabled = false;
var retrievedObject = localStorage.getItem('content');
editor.setMarkdown(retrievedObject);
}

@ -164,12 +164,15 @@ $(function () {
initEditor();
var editor;
var addWidgetButton;
function initEditor() {
var $editorContainer = $("#ContentEditor");
var inputName = $editorContainer.data('input-id');
var $editorInput = $('#' + inputName);
var initialValue = $editorInput.val();
addWidgetButton = createAddWidgetButton();
editor = new toastui.Editor({
el: $editorContainer[0],
usageStatistics: false,
@ -189,7 +192,7 @@ $(function () {
['code', 'codeblock'],
// Using Option: Customize the last button
[{
el: createAddWidgetButton(),
el: addWidgetButton,
command: 'bold',
tooltip: 'Add Widget'
}]
@ -255,20 +258,28 @@ $(function () {
editor.insertText(txt);
});
var $previewArea;
$('.tab-item').on('click', function () {
if ($(this).attr("aria-label") == 'Preview' && editor.isMarkdownMode()) {
if(!$previewArea){
$previewArea = $("#ContentEditor .toastui-editor-md-preview");
$previewArea.replaceWith("<iframe id='previewArea' style='height: 100%; width: 100%; border: 0px; display: inline;'></iframe>");
}
$previewArea.attr("srcdoc", '');
addWidgetButton.disabled = true;
let content = editor.getMarkdown();
localStorage.setItem('content', content);
$.post("/CmsKitCommonWidgets/ContentPreview", { content: content }, function (result) {
editor.setHTML(result);
var highllightedText = $('#ContentEditor').find('.toastui-editor-md-preview-highlight');
highllightedText.removeClass('toastui-editor-md-preview-highlight');
$previewArea = $("#previewArea");
$previewArea.attr("srcdoc", result);
});
}
else if ($(this).attr("aria-label") == 'Write') {
addWidgetButton.disabled = false;
var retrievedObject = localStorage.getItem('content');
editor.setMarkdown(retrievedObject);
}

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Volo.CmsKit.Contents;
@ -7,4 +8,11 @@ namespace Volo.CmsKit.Contents;
public class DefaultContentDto : IContent
{
public List<ContentFragment> ContentFragments { get; set; }
public bool AllowHtmlTags { get; set; } = true;
public bool PreventXSS { get; set; } = true;
[CanBeNull]
public string ReferralLink { get; set; } = null;
}

@ -4,5 +4,11 @@ namespace Volo.CmsKit.Contents;
public interface IContent
{
public List<ContentFragment> ContentFragments { get; set; }
List<ContentFragment> ContentFragments { get; set; }
bool AllowHtmlTags { get; set; }
bool PreventXSS { get; set; }
string ReferralLink { get; set; }
}

@ -25,7 +25,9 @@ public class ContentPreviewViewComponent : AbpViewComponent
return View("~/Pages/CmsKit/Components/ContentPreview/Default.cshtml", new DefaultContentDto
{
ContentFragments = fragments
ContentFragments = fragments,
AllowHtmlTags = true,
PreventXSS = false
});
}
}

@ -8,8 +8,5 @@
Layout = ThemeManager.CurrentTheme.GetEmptyLayout();
}
<abp-card>
<abp-card-body>
@await Component.InvokeAsync(typeof(ContentFragmentViewComponent), Model)
</abp-card-body>
</abp-card>
<div class="mt-3">@await Component.InvokeAsync(typeof(ContentFragmentViewComponent), Model)</div>

@ -14,7 +14,7 @@
{
if (contentFragment.Type == ContentConsts.Markdown)
{
@Html.Raw(await MarkdownRenderer.RenderAsync(contentFragment.GetProperty<string>("Content")))
@Html.Raw(await MarkdownRenderer.RenderAsync(contentFragment.GetProperty<string>("Content"), Model.ContentDto.AllowHtmlTags, Model.ContentDto.PreventXSS, Model.ContentDto.ReferralLink))
}
else if (contentFragment.Type == ContentConsts.Widget)
{

@ -3,5 +3,8 @@
public class BlogConsts
{
public static int MaxNameLength { get; set; } = 64;
public static int MaxSlugLength { get; set; } = 64;
public const string PreventXssFeatureName = "CmsKit.BlogPost.PreventXssFeature";
}

@ -3,7 +3,6 @@ using Volo.Abp.GlobalFeatures;
namespace Volo.CmsKit.GlobalFeatures;
[GlobalFeatureName(Name)]
public class BlogPostScrollIndexFeature : GlobalFeature
{

@ -15,6 +15,7 @@
"CmsKit.Ratings": "التقييمات",
"CmsKit.Reactions": "تفاعلات",
"CmsKit.Tags": "العلامات",
"CmsKit.BlogPost.PreventXssFeature": "منع XSS",
"CmsKit:0002": "المحتوى موجود بالفعل!",
"CmsKit:0003": "الكيان {0} غير قابل للعلامة.",
"CmsKit:Blog:0001": "slug المحدد ({Slug}) موجود بالفعل!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Hodnocení",
"CmsKit.Reactions": "Reakce",
"CmsKit.Tags": "Tagy",
"CmsKit.BlogPost.PreventXssFeature": "Zabraňte XSS",
"CmsKit:0002": "Obsah již existuje!",
"CmsKit:0003": "Entitu {0} nelze označit.",
"CmsKit:Blog:0001": "Daný slimák ({Slug}) již existuje!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Bewertungen",
"CmsKit.Reactions": "Reaktionen",
"CmsKit.Tags": "Stichworte",
"CmsKit.BlogPost.PreventXssFeature": "XSS-Prävention",
"CmsKit:0002": "Inhalt ist bereits vorhanden!",
"CmsKit:0003": "Die Entität {0} kann nicht mit Tags versehen werden.",
"CmsKit:Blog:0001": "Die angegebene Schnecke ({Slug}) existiert bereits!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Βαθμολογία",
"CmsKit.Reactions": "Αντιδράσεις",
"CmsKit.Tags": "Ετικέτες",
"CmsKit.BlogPost.PreventXssFeature": "Αποτροπή XSS",
"CmsKit:0002": "Το περιεχόμενο υπάρχει ήδη!",
"CmsKit:0003": "Η οντότητα {0} δεν μπορεί να επισημανθεί.",
"CmsKit:Blog:0001": "Το δεδομένο slug ({Slug}) υπάρχει ήδη!",

@ -1,228 +1,229 @@
{
"culture": "en",
"texts": {
"AddSubMenuItem": "Add Sub Menu Item",
"AreYouSure": "Are You Sure?",
"BlogDeletionConfirmationMessage": "The blog '{0}' will be deleted. Are you sure?",
"BlogFeatureNotAvailable": "This feature is not available now. Enable with 'GlobalFeatureManager' to use it.",
"BlogId": "Blog",
"BlogPostDeletionConfirmationMessage": "The blog post '{0}' will be deleted. Are you sure?",
"BlogPosts": "Blog Posts",
"Blogs": "Blogs",
"ChoosePreference": "Choose Preference...",
"Cms": "CMS",
"CmsKit.Comments": "Comments",
"CmsKit.Ratings": "Ratings",
"CmsKit.Reactions": "Reactions",
"CmsKit.Tags": "Tags",
"CmsKit:0002": "Content already exists!",
"CmsKit:0003": "The entity {0} is not taggable.",
"CmsKit:Blog:0001": "The given slug ({Slug}) already exists!",
"CmsKit:BlogPost:0001": "The given slug already exists!",
"CmsKit:Comments:0001": "The entity {EntityType} is not commentable.",
"CmsKit:Media:0001": "'{Name}' is not a valid media name.",
"CmsKit:Media:0002": "The entity can't have media.",
"CmsKit:Page:0001": "The given url ({Slug}) already exists. Please try with different url.",
"CmsKit:Rating:0001": "The entity {EntityType} can't be rated.",
"CmsKit:Reaction:0001": "The entity {EntityType} can't have reactions.",
"CmsKit:Tag:0002": "The entity is not taggable!",
"CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.",
"CommentDeletionConfirmationMessage": "This comment and all replies will be deleted!",
"Comments": "Comments",
"Content": "Content",
"ContentDeletionConfirmationMessage": "Are you sure to delete this content?",
"Contents": "Contents",
"CoverImage": "Cover Image",
"CreateBlogPostPage": "New Blog Post",
"CreationTime": "Creation Time",
"Delete": "Delete",
"Detail": "Detail",
"Details": "Details",
"DisplayName": "Display Name",
"DoYouPreferAdditionalEmails": "Do you prefer additional emails?",
"Edit": "Edit",
"EndDate": "End Date",
"EntityId": "Entity Id",
"EntityType": "Entity Type",
"ExportCSV": "Export CSV",
"Features": "Features",
"GenericDeletionConfirmationMessage": "Are you sure to delete '{0}'?",
"IsActive": "Active",
"LastModification": "Last Modification",
"LastModificationTime": "Last Modification Time",
"LoginToAddComment": "Login to add comment",
"LoginToRate": "Login to rate",
"LoginToReact": "Login to react",
"LoginToReply": "Login to reply",
"MainMenu": "Main Menu",
"MakeMainMenu": "Make Main Menu",
"Menu:CMS": "CMS",
"Menus": "Menus",
"MenuDeletionConfirmationMessage": "The menu '{0}' will be deleted. Are you sure?",
"MenuItemDeletionConfirmationMessage": "Are sure to delete this menu item?",
"MenuItemMoveConfirmMessage": "Are you sure you want to move '{0}' under '{1}'?",
"MenuItems": "Menu Items",
"Message": "Message",
"MessageDeletionConfirmationMessage": "This comment will be deleted completely.",
"NewBlog": "New Blog",
"NewBlogPost": "New Blog Post",
"NewMenu": "New Menu",
"NewMenuItem": "New Root Menu Item",
"NewPage": "New Page",
"NewTag": "New Tag",
"NoMenuItems": "There is no menu item yet!",
"OK": "OK",
"PageDeletionConfirmationMessage": "Are you sure to delete this page?",
"PageId": "Page",
"Pages": "Pages",
"PageSlugInformation": "Slug is used on url. Your url will be '/{{slug}}'.",
"Permission:BlogManagement": "Blog Management",
"Permission:BlogManagement.Create": "Create",
"Permission:BlogManagement.Delete": "Delete",
"Permission:BlogManagement.Features": "Features",
"Permission:BlogManagement.Update": "Update",
"Permission:BlogPostManagement": "Blog Post Management",
"Permission:BlogPostManagement.Create": "Create",
"Permission:BlogPostManagement.Delete": "Delete",
"Permission:BlogPostManagement.Update": "Update",
"Permission:BlogPostManagement.Publish": "Publish",
"Permission:CmsKit": "CmsKit Admin",
"Permission:Comments": "Comment Management",
"Permission:Comments.Delete": "Delete",
"Permission:Contents": "Content Management",
"Permission:Contents.Create": "Create Content",
"Permission:Contents.Delete": "Delete Content",
"Permission:Contents.Update": "Update Content",
"Permission:MediaDescriptorManagement": "Media Management",
"Permission:MediaDescriptorManagement:Create": "Create",
"Permission:MediaDescriptorManagement:Delete": "Delete",
"Permission:MenuItemManagement": "Menu Item Management",
"Permission:MenuItemManagement.Create": "Create",
"Permission:MenuItemManagement.Delete": "Delete",
"Permission:MenuItemManagement.Update": "Update",
"Permission:MenuManagement": "Menu Management",
"Permission:MenuManagement.Create": "Create",
"Permission:MenuManagement.Delete": "Delete",
"Permission:MenuManagement.Update": "Update",
"Permission:Menus": "Menu Management",
"Permission:Menus.Create": "Create",
"Permission:Menus.Delete": "Delete",
"Permission:Menus.Update": "Update",
"Permission:PageManagement": "Page Management",
"Permission:PageManagement:Create": "Create",
"Permission:PageManagement:Delete": "Delete",
"Permission:PageManagement:Update": "Update",
"Permission:PageManagement:SetAsHomePage": "Set As Home Page",
"Permission:TagManagement": "Tag Management",
"Permission:TagManagement.Create": "Create",
"Permission:TagManagement.Delete": "Delete",
"Permission:TagManagement.Update": "Update",
"Permission:GlobalResources": "Global Resources",
"Permission:CmsKitPublic": "CmsKit Public",
"Permission:Comments.DeleteAll": "Delete All",
"PickYourReaction": "Pick your reaction",
"Rating": "Rating",
"RatingUndoMessage": "Your rating will be undo.",
"Reactions": "Reactions",
"Read": "Read",
"RepliesToThisComment": "Replies to this comment",
"Reply": "Reply",
"ReplyTo": "Reply to",
"SamplePageMessage": "A sample page for the Pro module",
"SaveChanges": "Save Changes",
"Script": "Script",
"SelectAll": "Select All",
"Send": "Send",
"SendMessage": "Send Message",
"SelectedAuthor": "Author",
"ShortDescription": "Short description",
"Slug": "Slug",
"Source": "Source",
"SourceUrl": "Source Url",
"Star": "Star",
"StartDate": "Start Date",
"Style": "Style",
"Subject": "Subject",
"SubjectPlaceholder": "Please type a subject",
"Submit": "Submit",
"Subscribe": "Subscribe",
"SuccessfullySaved": "Successfully saved!",
"TagDeletionConfirmationMessage": "Are you sure to delete '{0}' tag?",
"Tags": "Tags",
"Text": "Text",
"ThankYou": "Thank you",
"Title": "Title",
"Undo": "Undo",
"Update": "Update",
"UpdatePreferenceSuccessMessage": "Your preferences have been saved.",
"UpdateYourEmailPreferences": "Update your email preferences",
"UnMakeMainMenu": "Unmake Main Menu",
"UploadFailedMessage": "Upload failed.",
"UserId": "User Id",
"Username": "Username",
"YourComment": "Your comment",
"YourEmailAddress": "Your e-mail address",
"YourFullName": "Your full name",
"YourMessage": "Your Message",
"YourReply": "Your reply",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.",
"GlobalResources": "Global Resources",
"SavedSuccessfully": "Saved successfully",
"CmsKit.BlogPost.Status.0": "Draft",
"CmsKit.BlogPost.Status.1": "Published",
"CmsKit.BlogPost.Status.2": "Waiting for review",
"BlogPostPublishConfirmationMessage": "Are you sure to publish the blog post \"{0}\"?",
"SuccessfullyPublished": "Successfully published!",
"Draft": "Draft",
"Publish": "Publish",
"BlogPostDraftConfirmationMessage": "Are you sure to set the blog post \"{0}\" as draft?",
"BlogPostSendToReviewConfirmationMessage": "Are you sure to send the blog post \"{0}\" to admin review for publishing?",
"SaveAsDraft": "Save as draft",
"SendToReview": "Send to review",
"SendToReviewToPublish": "Send to review to publish",
"BlogPostSendToReviewSuccessMessage": "The blog post \"{0}\" has been sent to admin review for publishing.",
"HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.",
"SelectAStatus": "Select a status",
"Status": "Status",
"CmsKit.BlogPost.ScrollIndex": "Quick navigation bar in blog posts",
"Add": "Add",
"AddWidget": "Add Widget",
"PleaseConfigureWidgets": "Please configure widgets",
"SelectAnAuthor": "Select an Author",
"InThisDocument": "In This Document",
"GoToTop": "Go To Top",
"SetAsHomePage": "Change Home Page Status",
"CompletedSettingAsHomePage": "Set as home page",
"IsHomePage": "Is Home Page",
"RemovedSettingAsHomePage": "Removed setting the home page",
"Feature:CmsKitGroup": "Cms Kit",
"Feature:BlogEnable": "Blogpost",
"Feature:BlogEnableDescription": "CMS Kit's blogpost system that allows create blogs and posts dynamically in the application.",
"Feature:CommentEnable": "Commenting",
"Feature:CommentEnableDescription": "CMS Kit's comment system allows commenting on entities such as BlogPost.",
"Feature:GlobalResourceEnable": "Global resourcing",
"Feature:GlobalResourceEnableDescription": "CMS Kit's global resoruces feature that allows managing global styles & scripts.",
"Feature:MenuEnable": "Menu",
"Feature:MenuEnableDescription": "CMS Kit's dynamic menu system that allows adding/removing application menus dynamically.",
"Feature:PageEnable": "Paging",
"Feature:PageEnableDescription": "CMS Kit's page system that allows creating static pages with specific URL.",
"Feature:RatingEnable": "Rating",
"Feature:RatingEnableDescription": "CMS Kit's rating system that allows users to rate entities such as BlogPost.",
"Feature:ReactionEnable": "Reaction",
"Feature:ReactionEnableDescription": "CMS Kit's reaction system that allows users to send reactions to entities such as BlogPost, Comments, etc.",
"Feature:TagEnable": "Taging",
"Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.",
"DeleteBlogPostMessage": "The blog will be deleted. Are you sure?",
"CaptchaCode": "Captcha code",
"CommentTextRequired": "Comment is required",
"CaptchaCodeErrorMessage": "The answer you entered for the CAPTCHA was not correct. Please try again",
"CaptchaCodeMissingMessage": "The captcha code is missing!",
"UnAllowedExternalUrlMessage": "You included an unallowed external URL. Please try again without the external URL.",
"URL": "URL",
"PopularTags": "Popular Tags",
"RemoveCoverImageConfirmationMessage": "Are you sure you want to remove the cover image?",
"RemoveCoverImage": "Remove cover image",
"CssClass": "CSS Class",
"TagsHelpText": "Tags should be comma-separated (e.g.: tag1, tag2, tag3)"
}
"texts": {
"AddSubMenuItem": "Add Sub Menu Item",
"AreYouSure": "Are You Sure?",
"BlogDeletionConfirmationMessage": "The blog '{0}' will be deleted. Are you sure?",
"BlogFeatureNotAvailable": "This feature is not available now. Enable with 'GlobalFeatureManager' to use it.",
"BlogId": "Blog",
"BlogPostDeletionConfirmationMessage": "The blog post '{0}' will be deleted. Are you sure?",
"BlogPosts": "Blog Posts",
"Blogs": "Blogs",
"ChoosePreference": "Choose Preference...",
"Cms": "CMS",
"CmsKit.Comments": "Comments",
"CmsKit.Ratings": "Ratings",
"CmsKit.Reactions": "Reactions",
"CmsKit.Tags": "Tags",
"CmsKit:0002": "Content already exists!",
"CmsKit:0003": "The entity {0} is not taggable.",
"CmsKit:Blog:0001": "The given slug ({Slug}) already exists!",
"CmsKit:BlogPost:0001": "The given slug already exists!",
"CmsKit:Comments:0001": "The entity {EntityType} is not commentable.",
"CmsKit:Media:0001": "'{Name}' is not a valid media name.",
"CmsKit:Media:0002": "The entity can't have media.",
"CmsKit:Page:0001": "The given url ({Slug}) already exists. Please try with different url.",
"CmsKit:Rating:0001": "The entity {EntityType} can't be rated.",
"CmsKit:Reaction:0001": "The entity {EntityType} can't have reactions.",
"CmsKit:Tag:0002": "The entity is not taggable!",
"CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.",
"CommentDeletionConfirmationMessage": "This comment and all replies will be deleted!",
"Comments": "Comments",
"Content": "Content",
"ContentDeletionConfirmationMessage": "Are you sure to delete this content?",
"Contents": "Contents",
"CoverImage": "Cover Image",
"CreateBlogPostPage": "New Blog Post",
"CreationTime": "Creation Time",
"Delete": "Delete",
"Detail": "Detail",
"Details": "Details",
"DisplayName": "Display Name",
"DoYouPreferAdditionalEmails": "Do you prefer additional emails?",
"Edit": "Edit",
"EndDate": "End Date",
"EntityId": "Entity Id",
"EntityType": "Entity Type",
"ExportCSV": "Export CSV",
"Features": "Features",
"GenericDeletionConfirmationMessage": "Are you sure to delete '{0}'?",
"IsActive": "Active",
"LastModification": "Last Modification",
"LastModificationTime": "Last Modification Time",
"LoginToAddComment": "Login to add comment",
"LoginToRate": "Login to rate",
"LoginToReact": "Login to react",
"LoginToReply": "Login to reply",
"MainMenu": "Main Menu",
"MakeMainMenu": "Make Main Menu",
"Menu:CMS": "CMS",
"Menus": "Menus",
"MenuDeletionConfirmationMessage": "The menu '{0}' will be deleted. Are you sure?",
"MenuItemDeletionConfirmationMessage": "Are sure to delete this menu item?",
"MenuItemMoveConfirmMessage": "Are you sure you want to move '{0}' under '{1}'?",
"MenuItems": "Menu Items",
"Message": "Message",
"MessageDeletionConfirmationMessage": "This comment will be deleted completely.",
"NewBlog": "New Blog",
"NewBlogPost": "New Blog Post",
"NewMenu": "New Menu",
"NewMenuItem": "New Root Menu Item",
"NewPage": "New Page",
"NewTag": "New Tag",
"NoMenuItems": "There is no menu item yet!",
"OK": "OK",
"PageDeletionConfirmationMessage": "Are you sure to delete this page?",
"PageId": "Page",
"Pages": "Pages",
"PageSlugInformation": "Slug is used on url. Your url will be '/{{slug}}'.",
"Permission:BlogManagement": "Blog Management",
"Permission:BlogManagement.Create": "Create",
"Permission:BlogManagement.Delete": "Delete",
"Permission:BlogManagement.Features": "Features",
"Permission:BlogManagement.Update": "Update",
"Permission:BlogPostManagement": "Blog Post Management",
"Permission:BlogPostManagement.Create": "Create",
"Permission:BlogPostManagement.Delete": "Delete",
"Permission:BlogPostManagement.Update": "Update",
"Permission:BlogPostManagement.Publish": "Publish",
"Permission:CmsKit": "CmsKit Admin",
"Permission:Comments": "Comment Management",
"Permission:Comments.Delete": "Delete",
"Permission:Contents": "Content Management",
"Permission:Contents.Create": "Create Content",
"Permission:Contents.Delete": "Delete Content",
"Permission:Contents.Update": "Update Content",
"Permission:MediaDescriptorManagement": "Media Management",
"Permission:MediaDescriptorManagement:Create": "Create",
"Permission:MediaDescriptorManagement:Delete": "Delete",
"Permission:MenuItemManagement": "Menu Item Management",
"Permission:MenuItemManagement.Create": "Create",
"Permission:MenuItemManagement.Delete": "Delete",
"Permission:MenuItemManagement.Update": "Update",
"Permission:MenuManagement": "Menu Management",
"Permission:MenuManagement.Create": "Create",
"Permission:MenuManagement.Delete": "Delete",
"Permission:MenuManagement.Update": "Update",
"Permission:Menus": "Menu Management",
"Permission:Menus.Create": "Create",
"Permission:Menus.Delete": "Delete",
"Permission:Menus.Update": "Update",
"Permission:PageManagement": "Page Management",
"Permission:PageManagement:Create": "Create",
"Permission:PageManagement:Delete": "Delete",
"Permission:PageManagement:Update": "Update",
"Permission:PageManagement:SetAsHomePage": "Set As Home Page",
"Permission:TagManagement": "Tag Management",
"Permission:TagManagement.Create": "Create",
"Permission:TagManagement.Delete": "Delete",
"Permission:TagManagement.Update": "Update",
"Permission:GlobalResources": "Global Resources",
"Permission:CmsKitPublic": "CmsKit Public",
"Permission:Comments.DeleteAll": "Delete All",
"PickYourReaction": "Pick your reaction",
"Rating": "Rating",
"RatingUndoMessage": "Your rating will be undo.",
"Reactions": "Reactions",
"Read": "Read",
"RepliesToThisComment": "Replies to this comment",
"Reply": "Reply",
"ReplyTo": "Reply to",
"SamplePageMessage": "A sample page for the Pro module",
"SaveChanges": "Save Changes",
"Script": "Script",
"SelectAll": "Select All",
"Send": "Send",
"SendMessage": "Send Message",
"SelectedAuthor": "Author",
"ShortDescription": "Short description",
"Slug": "Slug",
"Source": "Source",
"SourceUrl": "Source Url",
"Star": "Star",
"StartDate": "Start Date",
"Style": "Style",
"Subject": "Subject",
"SubjectPlaceholder": "Please type a subject",
"Submit": "Submit",
"Subscribe": "Subscribe",
"SuccessfullySaved": "Successfully saved!",
"TagDeletionConfirmationMessage": "Are you sure to delete '{0}' tag?",
"Tags": "Tags",
"Text": "Text",
"ThankYou": "Thank you",
"Title": "Title",
"Undo": "Undo",
"Update": "Update",
"UpdatePreferenceSuccessMessage": "Your preferences have been saved.",
"UpdateYourEmailPreferences": "Update your email preferences",
"UnMakeMainMenu": "Unmake Main Menu",
"UploadFailedMessage": "Upload failed.",
"UserId": "User Id",
"Username": "Username",
"YourComment": "Your comment",
"YourEmailAddress": "Your e-mail address",
"YourFullName": "Your full name",
"YourMessage": "Your Message",
"YourReply": "Your reply",
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.",
"GlobalResources": "Global Resources",
"SavedSuccessfully": "Saved successfully",
"CmsKit.BlogPost.Status.0": "Draft",
"CmsKit.BlogPost.Status.1": "Published",
"CmsKit.BlogPost.Status.2": "Waiting for review",
"BlogPostPublishConfirmationMessage": "Are you sure to publish the blog post \"{0}\"?",
"SuccessfullyPublished": "Successfully published!",
"Draft": "Draft",
"Publish": "Publish",
"BlogPostDraftConfirmationMessage": "Are you sure to set the blog post \"{0}\" as draft?",
"BlogPostSendToReviewConfirmationMessage": "Are you sure to send the blog post \"{0}\" to admin review for publishing?",
"SaveAsDraft": "Save as draft",
"SendToReview": "Send to review",
"SendToReviewToPublish": "Send to review to publish",
"BlogPostSendToReviewSuccessMessage": "The blog post \"{0}\" has been sent to admin review for publishing.",
"HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.",
"SelectAStatus": "Select a status",
"Status": "Status",
"CmsKit.BlogPost.ScrollIndex": "Quick navigation bar in blog posts",
"CmsKit.BlogPost.PreventXssFeature": "Prevent XSS",
"Add": "Add",
"AddWidget": "Add Widget",
"PleaseConfigureWidgets": "Please configure widgets",
"SelectAnAuthor": "Select an Author",
"InThisDocument": "In This Document",
"GoToTop": "Go To Top",
"SetAsHomePage": "Change Home Page Status",
"CompletedSettingAsHomePage": "Set as home page",
"IsHomePage": "Is Home Page",
"RemovedSettingAsHomePage": "Removed setting the home page",
"Feature:CmsKitGroup": "Cms Kit",
"Feature:BlogEnable": "Blogpost",
"Feature:BlogEnableDescription": "CMS Kit's blogpost system that allows create blogs and posts dynamically in the application.",
"Feature:CommentEnable": "Commenting",
"Feature:CommentEnableDescription": "CMS Kit's comment system allows commenting on entities such as BlogPost.",
"Feature:GlobalResourceEnable": "Global resourcing",
"Feature:GlobalResourceEnableDescription": "CMS Kit's global resoruces feature that allows managing global styles & scripts.",
"Feature:MenuEnable": "Menu",
"Feature:MenuEnableDescription": "CMS Kit's dynamic menu system that allows adding/removing application menus dynamically.",
"Feature:PageEnable": "Paging",
"Feature:PageEnableDescription": "CMS Kit's page system that allows creating static pages with specific URL.",
"Feature:RatingEnable": "Rating",
"Feature:RatingEnableDescription": "CMS Kit's rating system that allows users to rate entities such as BlogPost.",
"Feature:ReactionEnable": "Reaction",
"Feature:ReactionEnableDescription": "CMS Kit's reaction system that allows users to send reactions to entities such as BlogPost, Comments, etc.",
"Feature:TagEnable": "Taging",
"Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.",
"DeleteBlogPostMessage": "The blog will be deleted. Are you sure?",
"CaptchaCode": "Captcha code",
"CommentTextRequired": "Comment is required",
"CaptchaCodeErrorMessage": "The answer you entered for the CAPTCHA was not correct. Please try again",
"CaptchaCodeMissingMessage": "The captcha code is missing!",
"UnAllowedExternalUrlMessage": "You included an unallowed external URL. Please try again without the external URL.",
"URL": "URL",
"PopularTags": "Popular Tags",
"RemoveCoverImageConfirmationMessage": "Are you sure you want to remove the cover image?",
"RemoveCoverImage": "Remove cover image",
"CssClass": "CSS Class",
"TagsHelpText": "Tags should be comma-separated (e.g.: tag1, tag2, tag3)"
}
}

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Calificaciones",
"CmsKit.Reactions": "Reacciones",
"CmsKit.Tags": "Etiquetas",
"CmsKit.BlogPost.PreventXssFeature": "Prevenir ataques XSS",
"CmsKit:0002": "¡El contenido ya existe!",
"CmsKit:0003": "La entidad {0} no se puede etiquetar.",
"CmsKit:Blog:0001": "¡La babosa dada ({Slug}) ya existe!",

@ -181,6 +181,7 @@
"HasBlogPostWaitingForReviewMessage": "شما یک پست وبلاگ دارید که منتظر بررسی است. برای لیست کلیک کنید.",
"SelectAStatus": "انتخاب وضعیت",
"Status": "وضعیت",
"CmsKit.BlogPost.ScrollIndex": "نوار پیمایش سریع در پست های وبلاگ"
"CmsKit.BlogPost.ScrollIndex": "نوار پیمایش سریع در پست های وبلاگ",
"CmsKit.BlogPost.PreventXssFeature": "جلوگیری از XSS"
}
}

@ -185,6 +185,7 @@
"SelectAStatus": "Valitse tila",
"Status": "Tila",
"CmsKit.BlogPost.ScrollIndex": "Pikanavigointipalkki blogikirjoituksissa",
"CmsKit.BlogPost.PreventXssFeature": "Estä XSS",
"Add": "Lisää",
"AddWidget": "Lisää widget",
"PleaseConfigureWidgets": "Määritä widgetit",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Évaluations",
"CmsKit.Reactions": "Réactions",
"CmsKit.Tags": "Mots clés",
"CmsKit.BlogPost.PreventXssFeature": "Empêcher les attaques XSS",
"CmsKit:0002": "Le contenu existe déjà!",
"CmsKit:0003": "L'entité {0} ne peut pas être taguée.",
"CmsKit:Blog:0001": "Le slug donné ({Slug}) existe déjà!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "रेटिंग्स",
"CmsKit.Reactions": "प्रतिक्रियाओं",
"CmsKit.Tags": "टैग",
"CmsKit.BlogPost.PreventXssFeature": "XSS रोकें",
"CmsKit:0002": "सामग्री पहले से मौजूद है!",
"CmsKit:0003": "इकाई {0} टैग करने योग्य नहीं है।",
"CmsKit:Blog:0001": "दिया गया स्लग ({Slug}) पहले से मौजूद है!",

@ -182,6 +182,7 @@
"SelectAStatus": "Válasszon állapotot",
"Status": "Állapot",
"CmsKit.BlogPost.ScrollIndex": "Gyors navigációs sáv a blogbejegyzésekben",
"CmsKit.BlogPost.PreventXssFeature": "XSS megelőzése",
"Add": "Hozzáadás",
"AddWidget": "Widget hozzáadása",
"PleaseConfigureWidgets": "Kérjük, állítsa be a widgeteket",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Skor",
"CmsKit.Reactions": "Viðbrögð",
"CmsKit.Tags": "Tög",
"CmsKit.BlogPost.PreventXssFeature": "Fyrirbyggja XSS árásir",
"CmsKit:0002": "Efni nú þegar til!",
"CmsKit:0003": "Ekki hægt að tagga einingu {0}",
"CmsKit:Blog:0001": "Uppgefin snigill ({Slug}) er þegar til!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Valutazioni",
"CmsKit.Reactions": "Reazioni",
"CmsKit.Tags": "Tag",
"CmsKit.BlogPost.PreventXssFeature": "Prevenzione XSS",
"CmsKit:0002": "Il contenuto esiste già!",
"CmsKit:0003": "L'entità {0} non è codificabile.",
"CmsKit:Blog:0001": "Lo slug specificato ({Slug}) esiste già!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Beoordelingen",
"CmsKit.Reactions": "Reacties",
"CmsKit.Tags": "Tags",
"CmsKit.BlogPost.PreventXssFeature": "XSS-functie voorkomen",
"CmsKit:0002": "Inhoud bestaat al!",
"CmsKit:0003": "De entiteit {0} kan niet worden getagd.",
"CmsKit:Blog:0001": "De opgegeven slug ({Slug}) bestaat al!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Oceny",
"CmsKit.Reactions": "Reakcje",
"CmsKit.Tags": "Tagi",
"CmsKit.BlogPost.PreventXssFeature": "Zapobiegaj atakom XSS",
"CmsKit:0002": "Treść już istnieje!",
"CmsKit:0003": "Jednostka {0} nie może być otagowana.",
"CmsKit:Blog:0001": "Podany ślimak ({Slug}) już istnieje!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Avaliações",
"CmsKit.Reactions": "Reações",
"CmsKit.Tags": "Tag",
"CmsKit.BlogPost.PreventXssFeature": "Prevenir recurso XSS",
"CmsKit:0002": "O conteúdo já existe!",
"CmsKit:0003": "A entidade {0} não pode ser etiquetada.",
"CmsKit:Blog:0001": "O slug fornecido ({Slug}) já existe!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Evaluări",
"CmsKit.Reactions": "Reacţii",
"CmsKit.Tags": "Etichete",
"CmsKit.BlogPost.PreventXssFeature": "Prevenirea Xss",
"CmsKit:0002": "Conţinutul există deja!",
"CmsKit:0003": "Entitatea {0} nu este etichetabilă.",
"CmsKit:Blog:0001": "Slugul ({Slug}) există deja!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Рейтинги",
"CmsKit.Reactions": "Реакции",
"CmsKit.Tags": "Теги",
"CmsKit.BlogPost.PreventXssFeature": "Защита от XSS",
"CmsKit:0002": "Контент уже существует!",
"CmsKit:0003": "Сущность {0} не может быть помечена.",
"CmsKit:Blog:0001": "Указанный слаг ({Slug}) уже существует!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Hodnotenia",
"CmsKit.Reactions": "Reakcie",
"CmsKit.Tags": "Tagy",
"CmsKit.BlogPost.PreventXssFeature": "Zabraňte XSS",
"CmsKit:0002": "Obsah už existuje!",
"CmsKit:0003": "Entite {0} nie je možné priradiť tag.",
"CmsKit:Blog:0001": "Zadaný slug ({Slug}) už existuje!",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Ocene",
"CmsKit.Reactions": "Reakcije",
"CmsKit.Tags": "Oznake",
"CmsKit.BlogPost.PreventXssFeature": "Prepreči XSS",
"CmsKit:0002": "Vsebina že obstaja!",
"CmsKit:0003": "Entiteta {0} ni mogoče označiti.",
"CmsKit:Blog:0001": "Podani polž ({Slug}) že obstaja!",

@ -187,6 +187,7 @@
"RemoveCoverImageConfirmationMessage": "Kapak resmini kaldırmak istediğinize emin misiniz?",
"RemoveCoverImage": "Kapak resmini kaldır",
"CmsKit.BlogPost.ScrollIndex": "Blog yazılarında hızlı gezinme çubuğu",
"CmsKit.BlogPost.PreventXssFeature": "XSS önleme özelliği",
"Add": "Ekle",
"AddWidget": "Widget Ekle",
"PleaseConfigureWidgets": "Lütfen widget'leri yapılandırın",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "Xếp hạng",
"CmsKit.Reactions": "Phản ứng",
"CmsKit.Tags": "Thẻ",
"CmsKit.BlogPost.PreventXssFeature": "Ngăn chặn XSS",
"CmsKit:0002": "Nội dung đã tồn tại!",
"CmsKit:0003": "Thực thể {0} không thể gắn thẻ.",
"CmsKit:Blog:0001": "Sên đã cho ({Slug}) đã tồn tại!",

@ -185,6 +185,7 @@
"SelectAStatus": "选择一个状态",
"Status": "状态",
"CmsKit.BlogPost.ScrollIndex": "博客文章快速导航栏",
"CmsKit.BlogPost.PreventXssFeature": "防止XSS攻击",
"Add": "添加",
"AddWidget": "添加组件",
"PleaseConfigureWidgets": "请配置组件",

@ -15,6 +15,7 @@
"CmsKit.Ratings": "評分",
"CmsKit.Reactions": "反應",
"CmsKit.Tags": "標籤",
"CmsKit.BlogPost.PreventXssFeature": "防止XSS攻擊",
"CmsKit:0002": "內容已經存在!",
"CmsKit:0003": "實體 {0} 不可標記.",
"CmsKit:Blog:0001": "給定的slug ({Slug}) 已經存在!",

@ -11,12 +11,13 @@ public class DefaultBlogFeatureProvider : IDefaultBlogFeatureProvider, ITransien
public virtual Task<List<BlogFeature>> GetDefaultFeaturesAsync(Guid blogId)
{
return Task.FromResult(new List<BlogFeature>
{
new BlogFeature(blogId, CommentsFeature.Name),
new BlogFeature(blogId, ReactionsFeature.Name),
new BlogFeature(blogId, RatingsFeature.Name),
new BlogFeature(blogId, TagsFeature.Name),
new BlogFeature(blogId, BlogPostScrollIndexFeature.Name)
});
{
new BlogFeature(blogId, CommentsFeature.Name),
new BlogFeature(blogId, ReactionsFeature.Name),
new BlogFeature(blogId, RatingsFeature.Name),
new BlogFeature(blogId, TagsFeature.Name),
new BlogFeature(blogId, BlogPostScrollIndexFeature.Name),
new BlogFeature(blogId, BlogConsts.PreventXssFeatureName)
});
}
}

@ -204,7 +204,7 @@
{
@foreach (var reply in comment.Replies)
{
<div class="bg-light card p-3 mx-0 mt-3">
<div class="comment-container card p-3 mx-0 mt-3">
<div class="comment">
<h5>
@GetCommentTitle(reply.Author, reply.CreationTime).Invoke(null)

@ -69,7 +69,9 @@
</p>
@(await Component.InvokeAsync(typeof(ContentFragmentViewComponent), new DefaultContentDto
{
ContentFragments = Model.ViewModel.ContentFragments
ContentFragments = Model.ViewModel.ContentFragments,
AllowHtmlTags = true,
PreventXSS = Model.PreventXssFeature.IsEnabled,
}))
<p class="mb-3">
@if (Model.ViewModel.LastModificationTime != null)
@ -137,19 +139,19 @@
}
@if (isScrollIndexEnabled)
{
<div id="scroll-index" class="docs-inner-anchors mt-2">
<h5>@L["InThisDocument"]</h5>
<nav id="blog-post-sticky-index" class="navbar index-scroll pt-0">
</nav>
<div id="scroll-index" class="docs-inner-anchors mt-2">
<h5>@L["InThisDocument"]</h5>
<nav id="blog-post-sticky-index" class="navbar index-scroll pt-0">
</nav>
<div class="row">
<div class="col p-0 py-3">
<a href="#" class="scroll-top-btn">
<i class="fa fa-chevron-up"></i> @L["GoToTop"]
</a>
</div>
<div class="row">
<div class="col p-0 py-3">
<a href="#" class="scroll-top-btn">
<i class="fa fa-chevron-up"></i> @L["GoToTop"]
</a>
</div>
</div>
</div>
}
</div>

@ -29,6 +29,8 @@ public class BlogPostModel : CmsKitPublicPageModelBase
public BlogFeatureDto BlogPostScrollIndexFeature { get; private set; }
public BlogFeatureDto PreventXssFeature { get; private set; }
protected IBlogPostPublicAppService BlogPostPublicAppService { get; }
protected IBlogFeatureAppService BlogFeatureAppService { get; }
@ -81,6 +83,8 @@ public class BlogPostModel : CmsKitPublicPageModelBase
BlogPostScrollIndexFeature = await BlogFeatureAppService.GetOrDefaultAsync(ViewModel.BlogId, GlobalFeatures.BlogPostScrollIndexFeature.Name);
}
PreventXssFeature = await BlogFeatureAppService.GetOrDefaultAsync(ViewModel.BlogId, BlogConsts.PreventXssFeatureName);
return Page();
}
}

@ -7,23 +7,30 @@
@section styles{
<abp-style src="/Pages/Public/CmsKit/Pages/index.css" />
<style>
@Html.Raw(Model.ViewModel.Style)
</style>
@if (!Model.ViewModel.Style.IsNullOrEmpty())
{
<style>
@Html.Raw(Model.ViewModel.Style)
</style>
}
}
@section scripts{
<script>
@Html.Raw(Model.ViewModel.Script)
</script>
@if (!Model.ViewModel.Script.IsNullOrEmpty())
{
<script>
@Html.Raw(Model.ViewModel.Script)
</script>
}
}
<abp-card>
<abp-card-body>
@(await Component.InvokeAsync(typeof(ContentFragmentViewComponent), new DefaultContentDto
{
ContentFragments = Model.ViewModel.ContentFragments
ContentFragments = Model.ViewModel.ContentFragments,
PreventXSS = false,
AllowHtmlTags = true,
}))
</abp-card-body>
</abp-card>

@ -34,7 +34,7 @@
"build:schematics": "cd scripts && yarn && yarn build:schematics && cd ..",
"dev:schematics": "tsc -p packages/schematics/tsconfig.json -w",
"mock:schematics": "cd scripts/mock-schematic && yarn && yarn start",
"debug:schematics": "./node_modules/.bin/ng g ./packages/schematics/src/collection.json:proxy-add --module __default --apiName __default --source __default --target __default --url https://localhost:44305 --serviceType application --entryPoint __default ",
"debug:schematics": "./node_modules/.bin/nx g ./packages/schematics/src/collection.json:proxy-add --module identity --apiName __default --source __default --target __default --url https://localhost:44305 --serviceType application --entryPoint __default ",
"debug:schematics-dist": "./node_modules/.bin/ng g ./dist/packages/schematics/collection.json:proxy-add --module __default --apiName __default --source __default --target __default --url http://localhost:4300 --service-type application --entryPoint __default",
"ci": "yarn affected:lint && yarn affected:build && yarn affected:test",
"lerna": "lerna",

@ -9,6 +9,11 @@
"factory": "./src/generators/update-version/generator",
"schema": "./src/generators/update-version/schema.json",
"description": "update-version generator"
},
"change-theme": {
"factory": "./src/generators/change-theme/generator",
"schema": "./src/generators/change-theme/schema.json",
"description": "change-theme generator"
}
}
}

@ -0,0 +1,20 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Tree, readProjectConfiguration } from '@nx/devkit';
import { changeThemeGenerator } from './generator';
import { ChangeThemeGeneratorSchema } from './schema';
describe('change-theme generator', () => {
let tree: Tree;
const options: ChangeThemeGeneratorSchema = { name: 'test' };
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it('should run successfully', async () => {
await changeThemeGenerator(tree, options);
const config = readProjectConfiguration(tree, 'test');
expect(config).toBeDefined();
});
});

@ -0,0 +1,26 @@
import { Tree } from '@nx/devkit';
import { wrapAngularDevkitSchematic } from '@nx/devkit/ngcli-adapter';
import { ChangeThemeGeneratorSchema } from './schema';
import { ThemeOptionsEnum } from './theme-options.enum';
export async function changeThemeGenerator(host: Tree, schema: ChangeThemeGeneratorSchema) {
const schematicPath = schema.localPath || '@abp/ng.schematics';
const runAngularLibrarySchematic = wrapAngularDevkitSchematic(
schema.localPath ? `${host.root}${schematicPath}` : schematicPath,
'change-theme',
);
await runAngularLibrarySchematic(host, {
...schema,
});
return () => {
const destTheme = Object.values(ThemeOptionsEnum).find(
(theme, index) => index + 1 === schema.name,
);
console.log(`✅️ Switched to Theme ${destTheme}`);
};
}
export default changeThemeGenerator;

@ -0,0 +1,3 @@
export * from './theme-options.enum';
export * from './schema';
export * from './generator';

@ -0,0 +1,5 @@
export interface ChangeThemeGeneratorSchema {
name: number;
targetOption: string;
localPath?: string;
}

@ -0,0 +1,41 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "SchematicsABPThemeChanger",
"title": "ABP Theme Style Generator API Schema",
"type": "object",
"properties": {
"name": {
"description": "The name of theme will change.",
"type": "number",
"$default": {
"$source": "argv",
"index": 0
},
"enum": [1, 2, 3, 4],
"x-prompt": {
"message": "Which theme would you like to use?",
"type": "list",
"items": [
{ "value": 1, "label": "Basic" },
{ "value": 2, "label": "Lepton" },
{ "value": 3, "label": "LeptonXLite" },
{ "value": 4, "label": "LeptonX" }
]
}
},
"targetProject": {
"description": "The name of the project will change the style.The project type must be 'application'",
"type": "string",
"x-prompt": "Please enter the project name",
"$default": {
"$source": "argv",
"index": 1
}
},
"localPath": {
"description": "If set value schematics will work on given path",
"type": "string"
}
},
"required": ["name", "targetProject"]
}

@ -0,0 +1,8 @@
// this enum create by https://raw.githubusercontent.com/abpframework/abp/rel-7.4/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Theme.cs
export enum ThemeOptionsEnum {
Basic = 1,
Lepton = 2,
LeptonXLite = 3,
LeptonX = 4,
}

@ -1 +1,3 @@
export * from './generators/generate-proxy'
export * from './generators/change-theme';
export * from './generators/generate-proxy';
export * from './generators/update-version';

@ -1,10 +1,17 @@
import { Rule, SchematicsException } from '@angular-devkit/schematics';
import { isLibrary, updateWorkspace, WorkspaceDefinition } from '../../utils';
import { allStyles, styleMap } from './style-map';
import { ProjectDefinition } from '@angular-devkit/core/src/workspace';
import { JsonArray, JsonValue } from '@angular-devkit/core';
import { Rule, SchematicsException, Tree, chain } from '@angular-devkit/schematics';
import { ProjectDefinition } from '@angular-devkit/core/src/workspace';
import * as ts from 'typescript';
import { allStyles, importMap, styleMap } from './style-map';
import { ChangeThemeOptions } from './model';
import { Change, InsertChange, isLibrary, updateWorkspace, WorkspaceDefinition } from '../../utils';
import { ThemeOptionsEnum } from './theme-options.enum';
import {
addImportToModule,
findNodes,
getDecoratorMetadata,
getMetadataField,
} from '../../utils/angular/ast-utils';
export default function (_options: ChangeThemeOptions): Rule {
return async () => {
@ -14,9 +21,12 @@ export default function (_options: ChangeThemeOptions): Rule {
throw new SchematicsException('The theme name does not selected');
}
return updateWorkspace(storedWorkspace => {
updateProjectStyle(selectedProject, storedWorkspace, targetThemeName);
});
return chain([
updateWorkspace(storedWorkspace => {
updateProjectStyle(selectedProject, storedWorkspace, targetThemeName);
}),
updateAppModule(selectedProject, targetThemeName),
]);
};
}
@ -48,6 +58,138 @@ function updateProjectStyle(
targetOption.styles = [...newStyles, ...sanitizedStyles] as JsonArray;
}
function updateAppModule(selectedProject: string, targetThemeName: ThemeOptionsEnum): Rule {
return (host: Tree) => {
const angularJSON = host.read('angular.json');
if (!angularJSON) {
throw new SchematicsException('The angular.json does not found');
}
const workspace = JSON.parse(angularJSON.toString());
const project = workspace.projects[selectedProject];
if (!project || !project.sourceRoot) {
throw new SchematicsException('The target project does not found');
}
const appModulePath = project.sourceRoot + '/app/app.module.ts';
return chain([
removeImportPath(appModulePath, targetThemeName),
removeImportFromNgModuleMetadata(appModulePath, targetThemeName),
insertImports(appModulePath, targetThemeName),
]);
};
}
function removeImportPath(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule {
return (host: Tree) => {
const recorder = host.beginUpdate(appModulePath);
const sourceText = host.read(appModulePath)?.toString('utf-8');
const source = ts.createSourceFile(
appModulePath,
sourceText!,
ts.ScriptTarget.Latest,
true,
ts.ScriptKind.TS,
);
const impMap = Array.from(importMap.values())
.filter(f => f !== importMap.get(selectedTheme))
.reduce((acc, val) => [...acc, ...val], []);
const nodes = findNodes(source, ts.isImportDeclaration);
const filteredNodes = nodes.filter(n => impMap.some(f => n.getFullText().match(f.path)));
if (!filteredNodes || filteredNodes.length < 1) {
return;
}
filteredNodes.map(importPath =>
recorder.remove(importPath.getStart(), importPath.getWidth() + 1),
);
host.commitUpdate(recorder);
return host;
};
}
function removeImportFromNgModuleMetadata(
appModulePath: string,
selectedTheme: ThemeOptionsEnum,
): Rule {
return (host: Tree) => {
const recorder = host.beginUpdate(appModulePath);
const sourceText = host.read(appModulePath)?.toString('utf-8');
const source = ts.createSourceFile(
appModulePath,
sourceText!,
ts.ScriptTarget.Latest,
true,
ts.ScriptKind.TS,
);
const impMap = Array.from(importMap.values())
.filter(f => f !== importMap.get(selectedTheme))
.reduce((acc, val) => [...acc, ...val], []);
const node = getDecoratorMetadata(source, 'NgModule', '@angular/core')[0] || {};
if (!node) {
throw new SchematicsException('The app module does not found');
}
const matchingProperties = getMetadataField(node as ts.ObjectLiteralExpression, 'imports');
const assignment = matchingProperties[0] as ts.PropertyAssignment;
const assignmentInit = assignment.initializer as ts.ArrayLiteralExpression;
const elements = assignmentInit.elements;
if (!elements || elements.length < 1) {
return;
}
const filteredElements = elements.filter(f =>
impMap.some(s => f.getText().match(s.importName)),
);
if (!filteredElements || filteredElements.length < 1) {
return;
}
filteredElements.map(willRemoveModule =>
recorder.remove(willRemoveModule.getStart(), willRemoveModule.getWidth() + 1),
);
host.commitUpdate(recorder);
return host;
};
}
function insertImports(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule {
return (host: Tree) => {
const recorder = host.beginUpdate(appModulePath);
const sourceText = host.read(appModulePath)?.toString('utf-8');
const source = ts.createSourceFile(
appModulePath,
sourceText!,
ts.ScriptTarget.Latest,
true,
ts.ScriptKind.TS,
);
const selected = importMap.get(selectedTheme);
const changes: Change[] = [];
selected!.map(({ importName, path }) =>
changes.push(...addImportToModule(source, appModulePath, importName, path)),
);
if (changes.length > 0) {
for (const change of changes) {
if (change instanceof InsertChange) {
recorder.insertLeft(change.pos, change.toAdd);
}
}
}
host.commitUpdate(recorder);
return host;
};
}
export function getProjectTargetOptions(
project: ProjectDefinition,
buildTarget: string,

@ -8,6 +8,11 @@ export type StyleDefinition =
}
| string;
export type ImportDefinition = {
path: string;
importName: string;
};
export const styleMap = new Map<ThemeOptionsEnum, StyleDefinition[]>();
styleMap.set(ThemeOptionsEnum.Basic, [
@ -241,3 +246,49 @@ styleMap.set(ThemeOptionsEnum.LeptonXLite, [
]);
// the code written by Github co-pilot. thank go-pilot. You are the best sidekick.
export const allStyles = Array.from(styleMap.values()).reduce((acc, val) => [...acc, ...val], []);
export const importMap = new Map<ThemeOptionsEnum, ImportDefinition[]>();
importMap.set(ThemeOptionsEnum.Basic, [
{
path: '@abp/ng.theme.basic',
importName: 'ThemeBasicModule.forRoot()',
},
]);
importMap.set(ThemeOptionsEnum.Lepton, [
{
path: '@volo/abp.ng.theme.lepton',
importName: 'ThemeLeptonModule.forRoot()',
},
]);
importMap.set(ThemeOptionsEnum.LeptonXLite, [
{
path: '@abp/ng.theme.lepton-x',
importName: 'ThemeLeptonXModule.forRoot()',
},
{
path: '@abp/ng.theme.lepton-x/layouts',
importName: 'SideMenuLayoutModule.forRoot()',
},
{
path: '@abp/ng.theme.lepton-x/account',
importName: 'AccountLayoutModule.forRoot()',
},
]);
importMap.set(ThemeOptionsEnum.LeptonX, [
{
path: '@volosoft/abp.ng.theme.lepton-x',
importName: 'ThemeLeptonXModule.forRoot()',
},
{
path: '@volosoft/abp.ng.theme.lepton-x/layouts',
importName: 'SideMenuLayoutModule.forRoot()',
},
{
path: '@volosoft/abp.ng.theme.lepton-x/account',
importName: 'AccountLayoutModule.forRoot()',
},
]);

@ -446,7 +446,6 @@ export function addSymbolToNgModuleMetadata(
toInsert = `, ${symbolName}`;
}
}
if (importPath !== null) {
return [
new InsertChange(ngModulePath, position, toInsert),

@ -0,0 +1,129 @@
## Description
ABP Framework is a complete open-source infrastructure to create modern web applications by following the best practices and conventions of software development. This package is a part of the [ABP Framework](https://abp.io) and contains client-side files.
For more information, check out the below links:
🔗Official Website: https://abp.io
🔗Commercial Website: https://commercial.abp.io
🔗Commercial Demo: https://commercial.abp.io/demo
🔗GitHub Repository: https://github.com/abpframework/abp
🔗Official Theme: https://www.LeptonTheme.com
🔗Documentation: https://docs.abp.io
🔗Community: https://community.abp.io
🔗Blog: https://blog.abp.io
🔗Books: https://abp.io/books
🔗Twitter: https://twitter.com/abpframework
🔗Discord: https://community.abp.io/discord
🔗Stackoverflow: https://stackoverflow.com/questions/tagged/abp
🔗YouTube: https://www.youtube.com/@Volosoft
## 🤔 Why ABP Platform?
Why should you use the ABP.IO Platform instead of creating a new solution from scratch?
You can find the answer here 👉🏻 [Why ABP Platform?](https://docs.abp.io/en/commercial/latest/why-abp-io-platform)
## 🚀 Key Features of the ABP Framework
🟡 Modularity
🟡 Multi-Tenancy
🟡 Bootstrap Tag Helpers
🟡 Dynamic Forms
🟡 Authentication
🟡 Authorization
🟡 Distributed Event Bus
🟡 BLOB Storing
🟡 Text Templating
🟡 Tooling: ABP CLI
🟡 Cross-Cutting Concerns
🟡 Bundling & Minification
🟡 Virtual File System
🟡 Theming
🟡 Background Jobs
🟡 DDD Infrastructure
🟡 Auto REST APIs
🟡 Dynamic Client Proxies
🟡 Multiple Database Providers
🟡 Data filtering
🟡 Test Infrastructure
🟡 Audit Logging
🟡 Object to Object Mapping
🟡 Email & SMS Abstractions
🟡 Localization
🟡 Setting Management
🟡 Extension Methods
🟡 Aspect Oriented Programming
🟡 Dependency Injection
## 🧐 How It Works?
The following page explains how you use the ABP.IO Platform as a .NET developer 👉 [How it works?](https://commercial.abp.io/how-it-works)
### 📘 Supported Database Providers
🔵 Entity Framework Core
🔵 MongoDB
🔵 Dapper
### 🎴 Supported UI Frameworks
🔵 Angular
🔵 Razor Pages
🔵 Blazor Web Assembly
🔵 Blazor Server
🔵 MAUI with Blazor Hybrid
## 📫 Bug & Support
Support for open-source ABP Framework client-side packages is available at [GitHub Issues](https://github.com/abpframework/abp/issues), and the commercial support is available at [support.abp.io](https://support.abp.io).

@ -0,0 +1,5 @@
module.exports = {
mappings: {
"@node_modules/zxcvbn/dist/zxcvbn.js": "@libs/zxcvbn/"
}
}

@ -0,0 +1,32 @@
{
"version": "7.4.0-rc.3",
"name": "@abp/zxcvbn",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@abp/core": "~7.4.0-rc.3",
"zxcvbn" : "^4.4.2"
},
"gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431",
"homepage": "https://abp.io",
"repository": {
"type": "git",
"url": "https://github.com/abpframework/abp.git"
},
"license": "LGPL-3.0",
"keywords": [
"aspnetcore",
"boilerplate",
"framework",
"web",
"best-practices",
"angular",
"maui",
"blazor",
"mvc",
"csharp",
"webapp"
]
}

@ -20,7 +20,7 @@
"@abp/ng.setting-management": "~7.4.0-rc.3",
"@abp/ng.tenant-management": "~7.4.0-rc.3",
"@abp/ng.theme.shared": "~7.4.0-rc.3",
"@abp/ng.theme.lepton-x": "~2.4.0-rc.2",
"@abp/ng.theme.lepton-x": "~2.4.0-rc.3",
"@angular/animations": "~16.0.0",
"@angular/common": "~16.0.0",
"@angular/compiler": "~16.0.0",

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save