Browse Source

Merge branch 'dev' into maliming/IdentityClientConfiguration

pull/9675/head
maliming 5 years ago
parent
commit
1c1daca10f
  1. 26
      .github/workflows/angular.yml
  2. 2
      .github/workflows/build-and-test.yml
  3. 12
      .github/workflows/cancel-workflow.yml
  4. 16
      .github/workflows/codeql-analysis.yml
  5. 2
      Directory.Build.props
  6. 14
      abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ro-RO.json
  7. 9
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json
  8. 308
      abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json
  9. 8
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json
  10. 40
      abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ro-RO.json
  11. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ro-RO.json
  12. 34
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  13. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json
  14. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json
  15. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json
  16. 25
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json
  17. 363
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json
  18. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json
  19. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json
  20. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json
  21. 147
      abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json
  22. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/ro-RO.json
  23. 5
      abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/ro-RO.json
  24. 278
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json
  25. 4
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json
  26. 14
      common.props
  27. 140
      docs/en/API/Swagger-Integration.md
  28. 2
      docs/en/Authorization.md
  29. 23
      docs/en/Background-Jobs-Hangfire.md
  30. 29
      docs/en/Best-Practices/Entity-Framework-Core-Integration.md
  31. 26
      docs/en/Best-Practices/MongoDB-Integration.md
  32. 2
      docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md
  33. 216
      docs/en/Blog-Posts/2021-07-28-lepton-x-release/POST.md
  34. BIN
      docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-dashboard.png
  35. BIN
      docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-menu-collapsed.png
  36. 42
      docs/en/Blog-Posts/2021-08-02 v4_4_Release_Stable/POST.md
  37. 13
      docs/en/CLI.md
  38. 2
      docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md
  39. 46
      docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md
  40. 6
      docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md
  41. 2
      docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md
  42. 2
      docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md
  43. 3
      docs/en/Concurrency-Check.md
  44. 8
      docs/en/Dapper.md
  45. 35
      docs/en/Data-Filtering.md
  46. 8
      docs/en/Data-Transfer-Objects.md
  47. 7
      docs/en/Modules/Docs.md
  48. 6
      docs/en/Modules/Permission-Management.md
  49. 2
      docs/en/Modules/Setting-Management.md
  50. 5
      docs/en/Modules/Virtual-File-Explorer.md
  51. 9
      docs/en/Road-Map.md
  52. 4
      docs/en/SignalR-Integration.md
  53. 3
      docs/en/Swagger.md
  54. 2
      docs/en/Text-Templating-Scriban.md
  55. 2
      docs/en/Tutorials/Part-9.md
  56. 2
      docs/en/Tutorials/Todo/Index.md
  57. 67
      docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md
  58. 276
      docs/en/UI/Angular/Permission-Management-Component-Replacement.md
  59. 2
      docs/en/UI/Angular/Settings.md
  60. 4
      docs/en/UI/AspNetCore/Basic-Theme.md
  61. 16
      docs/en/UI/AspNetCore/Client-Side-Package-Management.md
  62. 4
      docs/en/UI/Blazor/Customization-Overriding-Components.md
  63. 7
      docs/en/Validation.md
  64. 4
      docs/en/docs-nav.json
  65. 33
      docs/zh-Hans/Data-Filtering.md
  66. 8
      docs/zh-Hans/Data-Transfer-Objects.md
  67. 2
      docs/zh-Hans/Entities.md
  68. 5
      docs/zh-Hans/Modules/Docs.md
  69. 5
      docs/zh-Hans/Modules/Virtual-File-Explorer.md
  70. 4
      docs/zh-Hans/SignalR-Integration.md
  71. 830
      docs/zh-Hans/Tutorials/Todo/Index.md
  72. 0
      docs/zh-Hans/Tutorials/Todo/run-without-iisexpress.png
  73. 0
      docs/zh-Hans/Tutorials/Todo/todo-api.png
  74. BIN
      docs/zh-Hans/Tutorials/Todo/todo-efcore-migration.png
  75. 0
      docs/zh-Hans/Tutorials/Todo/todo-list.png
  76. 0
      docs/zh-Hans/Tutorials/Todo/todo-swagger-ui-initial.png
  77. 0
      docs/zh-Hans/Tutorials/Todo/todo-ui-initial.png
  78. 822
      docs/zh-Hans/Tutorials/todo/Index.md
  79. BIN
      docs/zh-Hans/Tutorials/todo/todo-efcore-migration.png
  80. 16
      docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md
  81. 7
      docs/zh-Hans/Validation.md
  82. 4
      docs/zh-Hans/docs-nav.json
  83. 2
      docs/zh-Hans/docs-params.json
  84. 7
      framework/Volo.Abp.sln
  85. 0
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs
  86. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj
  87. 27
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Properties/launchSettings.json
  88. 3
      framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj
  89. 2
      framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj
  90. 3
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj
  91. 3
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
  92. 11
      framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
  93. 0
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs
  94. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.csproj
  95. 2
      framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.csproj
  96. 0
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsComponentsBundleContributor.cs
  97. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj
  98. 2
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj
  99. 2
      framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.csproj
  100. 2
      framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.csproj

26
.github/workflows/angular.yml

@ -12,9 +12,11 @@ on:
- 'dev'
jobs:
build-test-lint:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/cache@v2
with:
@ -31,25 +33,13 @@ jobs:
working-directory: npm/ng-packs
- name: Run lint
run: yarn ng lint
run: yarn affected:lint --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs
- name: Run prepare workspace
run: yarn prepare:workspace
- name: Run build
run: yarn affected:build --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs
- name: Run test
run: yarn ci:test
working-directory: npm/ng-packs
- name: Build dev-app
run: yarn build --prod
run: yarn affected:test --base=remotes/origin/${{ github.base_ref }}
working-directory: npm/ng-packs
- name: Install packages of app template
run: yarn install
working-directory: templates/app/angular
- name: Build app template
run: yarn build --prod
working-directory: templates/app/angular

2
.github/workflows/build-and-test.yml

@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-dotnet@master
with:
dotnet-version: 5.0.201
dotnet-version: 6.0.100-rc.1.21458.32
- name: Build All
run: .\build-all.ps1

12
.github/workflows/cancel-workflow.yml

@ -0,0 +1,12 @@
name: cancel-workflow
on: [push]
jobs:
cancel:
name: 'Cancel Previous Runs'
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- uses: styfle/cancel-workflow-action@0.6.0
with:
workflow_id: 10629,1299107,2792859,8268314
access_token: ${{ github.token }}

16
.github/workflows/codeql-analysis.yml

@ -7,12 +7,22 @@ name: "CodeQL"
on:
push:
branches: [dev, rel-1.0, rel-1.1, rel-2.0, rel-2.1, rel-2.2, rel-2.3, rel-2.4, rel-2.5, rel-2.6, rel-2.7, rel-2.8, rel-2.9, rel-3.0, rel-3.1, rel-3.2]
branches: [dev, rel-*]
paths:
- 'abp/**/*.js'
- 'abp/**/*.cs'
- 'abp/**/*.cshtml'
- 'abp/**/*.csproj'
- 'abp/**/*.razor'
pull_request:
# The branches below must be a subset of the branches above
branches: [dev]
schedule:
- cron: '0 8 * * 6'
paths:
- 'abp/**/*.js'
- 'abp/**/*.cs'
- 'abp/**/*.cshtml'
- 'abp/**/*.csproj'
- 'abp/**/*.razor'
jobs:
analyze:

2
Directory.Build.props

@ -2,7 +2,7 @@
<PropertyGroup>
<!-- All Microsoft packages -->
<MicrosoftPackageVersion>5.0.*</MicrosoftPackageVersion>
<MicrosoftPackageVersion>6.0.0-rc.*</MicrosoftPackageVersion>
<!-- Microsoft.NET.Test.Sdk https://www.nuget.org/packages/Microsoft.NET.Test.Sdk -->
<MicrosoftNETTestSdkPackageVersion>16.9.1</MicrosoftNETTestSdkPackageVersion>

14
abp_io/AbpIoLocalization/AbpIoLocalization/Account/Localization/Resources/ro-RO.json

@ -0,0 +1,14 @@
{
"culture": "ro-RO",
"texts": {
"Account": "Cont ABP - Autentificare & Înregistrare | ABP.IO",
"Welcome": "Bun venit",
"UseOneOfTheFollowingLinksToContinue": "Folosiţi unul din următoarele linkuri pentru a continua",
"FrameworkHomePage": "Pagina principală a frameworkului",
"FrameworkDocumentation": "Documentaţia frameworkului",
"OfficialBlog": "Blogul oficial",
"CommercialHomePage": "Pagina principală comercială",
"CommercialSupportWebSite": "Site-ul web al suportului comercial",
"CommunityWebSite": "Site-ul web al comunităţii ABP"
}
}

9
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/en.json

@ -303,6 +303,13 @@
"ProductPrice": "Product Price",
"AdditionalDeveloper": "Additional developer",
"ThisPaymentHasBeenAlreadyUsed": "This payment has been already used",
"PaymentTimeCannotBeFutureTime": "Payment time cannot be future time"
"PaymentTimeCannotBeFutureTime": "Payment time cannot be a future time!",
"SaveAndDownload": "Save and Download",
"BillingInfo": "Billing Info",
"GenerateInvoice": "Create Invoice",
"DeleteInvoice" : "Delete Invoice",
"SuccessfullyDeleted": "Successfully deleted!",
"PaymentStateSetTo" : "Payment state set to {0}",
"ChangeState": "Change State"
}
}

308
abp_io/AbpIoLocalization/AbpIoLocalization/Admin/Localization/Resources/ro-RO.json

@ -0,0 +1,308 @@
{
"culture": "ro-RO",
"texts": {
"Permission:Organizations": "Organizaţii",
"Permission:Manage": "Administrare Organizaţii",
"Permission:DiscountRequests": "Cereri de reduceri",
"Permission:DiscountManage": "Administrare cereri de reduceri",
"Permission:Disable": "Dezactivează",
"Permission:Enable": "Activează",
"Permission:EnableSendEmail": "Activează trimitere Email",
"Permission:SendEmail": "Trimite Email",
"Permission:NpmPackages": "Pachete NPM",
"Permission:NugetPackages": "Pachete Nuget",
"Permission:Maintenance": "Întreţinere",
"Permission:Maintain": "Întreţine",
"Permission:ClearCaches": "Goleşte cache-ul",
"Permission:Modules": "Module",
"Permission:Packages": "Pachete",
"Permission:Edit": "Modifică",
"Permission:Delete": "Şterge",
"Permission:Create": "Creează",
"Permission:Accounting": "Contabilitate",
"Permission:Accounting:Quotation": "Citat",
"Permission:Accounting:Invoice": "Factură",
"Menu:Organizations": "Organizaţii",
"Menu:Accounting": "Contabilitate",
"Menu:Packages": "Pachete",
"Menu:DiscountRequests": "Cereri de reduceri",
"NpmPackageDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest pachet de tip NPM?",
"NugetPackageDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest pachet de tip Nuget?",
"ModuleDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi acest modul?",
"Name": "Nume",
"DisplayName": "Nume de afişare",
"ShortDescription": "Descriere scurtă",
"NameFilter": "Nume",
"CreationTime": "Data şi ora creării",
"IsPro": "Este pro",
"IsFreeToActiveLicenseOwners": "Gratuit pentru deţinătorii de licenţă",
"ShowOnModuleList": "Afişează în lista modulelor",
"EfCoreConfigureMethodName": "Configurează numele metodei",
"IsProFilter": "Este pro",
"ApplicationType": "Tipul aplicaţiei",
"Target": "Ţinta",
"TargetFilter": "Ţinta",
"ModuleClass": "Clasa modulului",
"NugetPackageTarget.DomainShared": "Domain Shared",
"NugetPackageTarget.Domain": "Domain",
"NugetPackageTarget.Application": "Application",
"NugetPackageTarget.ApplicationContracts": "Application Contracts",
"NugetPackageTarget.HttpApi": "Http Api",
"NugetPackageTarget.HttpApiClient": "Http Api Client",
"NugetPackageTarget.Web": "Web",
"NugetPackageTarget.EntityFrameworkCore": "DeleteAllEntityFramework Core",
"NugetPackageTarget.MongoDB": "MongoDB",
"Edit": "Modifică",
"Delete": "Şterge",
"Refresh": "Reîncarcă",
"NpmPackages": "Pachete NPM",
"NugetPackages": "Pachete Nuget",
"NpmPackageCount": "Număr pachete NPM",
"NugetPackageCount": "Număr pachete Nuget",
"Module": "Module",
"ModuleInfo": "Info module",
"CreateANpmPackage": "Crează un pachet NPM",
"CreateAModule": "Crează un modul",
"CreateANugetPackage": "Crează un pachet Nuget",
"AddNew": "Adaugă o înregistrare nouă",
"PackageAlreadyExist{0}": "Pachetul \"{0}\" este deja adăugat.",
"ModuleAlreadyExist{0}": "Modulul \"{0}\" este deja adăugat.",
"ClearCache": "Goleşte cache",
"SuccessfullyCleared": "Golit cu succes",
"Menu:NpmPackages": "Pachete de tip NPM",
"Menu:Modules": "Module",
"Menu:Maintenance": "Mentenanţă",
"Menu:NugetPackages": "Pachete de tip Nuget",
"CreateAnOrganization": "Crează o organizaţie",
"Organizations": "Organizaţii",
"LongName": "Nume complet",
"LicenseType": "Tipul licenţei",
"MissingLicenseTypeField": "Câmpul de tip licenţă este obligatoriu!",
"LicenseStartTime": "Ora de început a licenţei",
"LicenseEndTime": "Ora de sfârşit a licenţei",
"AllowedDeveloperCount": "Număr permis de dezvoltatori",
"UserNameOrEmailAddress": "Numele de utilizator sau adresa de email",
"AddOwner": "Adaugă proprietar",
"UserName": "Nume de utilizator",
"Email": "Email",
"Developers": "Dezvoltatori",
"AddDeveloper": "Adaugă dezvoltator",
"Create": "Creează",
"UserNotFound": "Utilizatorul nu a fost găsit",
"{0}WillBeRemovedFromDevelopers": "{0} va fi eliminat dintre dezvoltatori, confirmaţi?",
"{0}WillBeRemovedFromOwners": "{0} va fi eliminat dintre proprietari, confirmaţi?",
"{0}WillBeRemovedFromMembers": "{0} va fi eliminat dintre membri, confirmaţi?",
"Computers": "Calculatoare",
"UniqueComputerId": "Identificator unic calculator",
"LastSeenDate": "Data ultimei accesări",
"{0}Computer{1}WillBeRemovedFromRecords": "Calculatorul {0} ({1}) va fi eliminat dintre înregistrări",
"OrganizationDeletionWarningMessage": "Organizaţia va fi ştearsă",
"DeletingLastOwnerWarningMessage": "Organizaţia trebuie să aibă cel puţin un proprietar! Prin urmare nu puteţi şterge acest proprietar.",
"This{0}AlreadyExistInThisOrganization": "Acest(a) {0} există deja în această organizaţie",
"AreYouSureYouWantToDeleteAllComputers": "Sunteţi sigur(ă) că doriţi să ştergeţi toate calculatoarele?",
"DeleteAll": "Şterge tot",
"DoYouWantToCreateNewUser": "Vreţi să creaţi un nou utilizator?",
"MasterModules": "Module master",
"OrganizationName": "Nume organizaţie",
"CreationDate": "Data creării",
"LicenseStartDate": "Data de început a licenţei",
"LicenseEndDate": "Data de sfărşit a licenţei",
"OrganizationNamePlaceholder": "Numele organizaţiei...",
"TotalQuestionCountPlaceholder": "Numărul total de înrebări...",
"RemainingQuestionCountPlaceholder": "Numărul de întrebări rămase...",
"LicenseTypePlaceholder": "Tipul licenţei...",
"CreationDatePlaceholder": "Data creării...",
"LicenseStartDatePlaceholder": "Data de început a licenţei...",
"LicenseEndDatePlaceholder": "Data de sfârşit a licenţei...",
"UsernameOrEmail": "Nume de utilizator sau email",
"UsernameOrEmailPlaceholder": "Nume de utilizator sau email...",
"Member": "Membru",
"PurchaseOrderNo": "Achiziţia numărul",
"QuotationDate": "Data citării",
"CompanyName": "Nume companie",
"CompanyAddress": "Adresă companie",
"Price": "Preţ",
"DiscountText": "Text discount",
"DiscountQuantity": "Cantitate discount",
"DiscountPrice": "Preţ discount",
"Quotation": "Citare",
"ExtraText": "Text extra",
"ExtraAmount": "Cantitate extra",
"DownloadQuotation": "Descarcă citarea",
"Invoice": "Factură",
"TaxNumber": "Număr taxă",
"InvoiceNumber": "Număr factură",
"InvoiceDate": "Dată factură",
"InvoiceNote": "Notă factură",
"Quantity": "Cantitate",
"AddProduct": "Adaugă produs",
"AddProductWarning": "Trebuie să adăugaţi un produs!",
"TotalPrice": "Preţ total",
"Generate": "Generează",
"MissingQuantityField": "Câmpul de cantitate este obligatoriu!",
"MissingPriceField": "Câmpul de preţ este obligatoriu!",
"CodeUsageStatus": "Stare",
"Country": "Ţara",
"DeveloperCount": "Număr dezvoltatori",
"RequestCode": "Cod solicitare",
"WebSite": "Web Site",
"GithubUsername": "Nume utilizator de Github",
"PhoneNumber": "Număr de telefon",
"ProjectDescription": "Descriere proiect",
"Referrer": "Referent",
"DiscountRequests": "Cerere de reducere",
"Copylink": "Copiază linkul",
"Disable": "Dezactivează",
"Enable": "Activează",
"EnableSendEmail": "Activează trimitere Email",
"SendEmail": "Trimite Email",
"SuccessfullyDisabled": "Dezactivat cu succes",
"SuccessfullyEnabled": "Activat cu succes",
"EmailSent": "Email trimis",
"SuccessfullySent": "Trimis cu succes",
"SuccessfullyDeleted": "Şters cu succes",
"DiscountRequestDeletionWarningMessage": "Cererea de reducere va fi ştearsă",
"BusinessType": "Tip afacere",
"TotalQuestionCount": "Număr total de întrebări",
"RemainingQuestionCount": "Număr de întrebări rămase",
"TotalQuestionMustBeGreaterWarningMessage": "Numărul total de întrebări trebuie să fie mai mare decât numărul de întrebări rămase!",
"QuestionCountsMustBeGreaterThanZero": "Numărul total de întrebări şi numărul de întrebări rămase trebuie să fie mai mai mare sau egal cu 0!",
"UnlimitedQuestionCount": "Număr nelimitat de întrebări",
"Notes": "Notiţe",
"Menu:Community": "Comunitate",
"Menu:Articles": "Articole",
"Wait": "Aşteaptă",
"Approve": "Aprobă",
"Reject": "Respinge",
"Details": "Detalii",
"Url": "Url",
"Title": "Titlu",
"ContentSource": "Sursa conţinutului",
"Status": "Status",
"ReadArticle": "Citeşte articolul",
"ArticleHasBeenWaiting": "Articolul a fost în aşteptare",
"ArticleHasBeenApproved": "Articolul a fost aprobat",
"ArticleHasBeenRejected": "Articolul a fost respins",
"Permission:Community": "Comunitate",
"Permission:CommunityArticle": "Articole",
"Link": "Link",
"Enum:ContentSource:0": "Github",
"Enum:ContentSource:1": "External",
"Enum:Status:0": "Aşteptare",
"Enum:Status:1": "Respins",
"Enum:Status:2": "Aprobat",
"Summary": "Sumar",
"AuthorName": "Nume autor",
"CoverImage": "Imagine de copertă",
"RemoveCacheConfirmationMessage": "Sunteţi sigur(ă) că doriţi să eliminaţi cache-ul pentru articolul \"{0}\"?",
"SuccessfullyRemoved": "Eliminat cu succes",
"RemoveCache": "Elimină cache",
"Language": "Limba",
"Optional": "Opţional",
"CreateArticleLanguageInfo": "Limba în care este scris articolul",
"Enum:ContentSource:2": "Post Video",
"VideoPreview": "Previzualizare Video",
"VideoPreviewErrorMessage": "Adresa URL a clipului video nu a putut fi recuperată de pe Youtube. Acest lucru poate fi cauzat de faptul că videoclipul este privat, sau adresa URL nu este disponibilă.",
"DeleteCoverImage": "Şterge imaginea de copertă",
"DeleteCoverImageConfirmationMessage": "Sunteţi sigur(ă) că doriţi să ştergeti imaginea de copertă pentru \"{0}\"?",
"DeleteCoverImageSuccessMessage": "Imaginea de copertă a fost ştearsă cu succes",
"PaymentsOf": "Plăţi de",
"ShowPaymentsOfOrganization": "Plăţi",
"Date": "Data",
"Products": "Produse",
"TotalAmount": "Cantitate totală",
"Currency": "Valută",
"Gateway": "Gateway",
"State": "Stare",
"FailReason": "Motivul eşuării",
"ReIndexAllPosts": "Reindexati toate postările",
"ReIndexAllPostsConfirmationMessage": "Sunteţi sigur(ă) că doriţi să reindexaţi toate postările?",
"SuccessfullyReIndexAllPosts": "Toate postările au fost reindexate.",
"Permission:FullSearch": "Căutare integrală a textului",
"Menu:CliAnalytics": "Analitice Cli",
"TemplateName": "Nume şablon",
"TemplateVersion": "Versiune şablon",
"DatabaseProvider": "Furnizor bază de date",
"IsTiered": "Este nivelat",
"ProjectName": "Nume proiect",
"Username": "Nume utilizator",
"Tool": "Unealtă",
"Command": "Comandă",
"UiFramework": "Ui framework",
"Options": "Opţiuni",
"CliAnalytics": "Analitice Cli",
"Permission:CliAnalyticses": "Analitice Cli",
"Permission:CliAnalytics": "Analitice Cli",
"Search": "Caută",
"ClearFilter": "Şterge filtru",
"LicensePrivateKey": "Cheie privată licenţă",
"LicensePublicKey": "Cheie publică licenţă",
"ApiKey": "Cheie API NuGet",
"ShowInvoiceRequestsOfOrganization": "Solicitări de factură",
"ShowQuestionsOfOrganization": "Întrebări",
"Question": "Întrebare",
"Open": "Deschide",
"Questions": "Întrebări",
"InvoiceRequests": "Solicitări de factură",
"Address": "Adresa",
"TaxNo": "Taxa numărul",
"Permission:InvoiceRequest": "Solicitare de factură",
"Permission:Question": "Întrebare",
"AddNoteSuccessMessage": "Notă adăugată cu succes",
"NameSurname": "Nume Prenume",
"Note": "Notează",
"Add": "Adaugă",
"ProjectDownloads": "Descărcările proiectului",
"ShowProjectDownloadsOfOrganization": "Descărcările proiectului",
"ShowAuditLogsOfOrganization": "Jurnale de audit",
"Enum:EntityChangeType:0": "Creat",
"Enum:EntityChangeType:1": "Actualizat",
"Enum:EntityChangeType:2": "Şters",
"TenantId": "ID Tenant",
"ChangeTime": "Schimbă ora",
"EntityTypeFullName": "Numele complet al tipului entităţii",
"AuditLogsFor{0}Organization": "Jurnale de audit pentru organizaţia \"{0}\"",
"Permission:EntityChange": "Schimbă entitatea",
"Permission:ProjectDownload": "Descarcă proiectul",
"Permission:PaymentRequest": "Solicitări de plată",
"CreatorEmailAddress": "Adresa de email a creatorului",
"EmailSendDate": "Data trimiterii emailului",
"PaymentRequestsFor{0}Organization": "Solicitări de plată pentru organizaţia \"{0}\"",
"PaymentDetails": "Detalii plată",
"PaymentProduct": "Produs plată",
"ProductName": "Nume produs",
"Code": "Cod",
"GenerateInvoice": "Generează factură",
"ExportOrganizationsToExcel": "Exportă în Excel",
"ThisExtensionIsNotAllowed": "Această extensie nu este permisă.",
"TheFileIsTooLarge": "Dimensiunea fişierului este prea mare!",
"ArticleDeletionConfirmationMessage": "Sunteţi sigur(ă) că doriţi şă ştergeţi definitiv acest articol?",
"ChooseCoverImage": "Alege o imagine de copertă...",
"Menu:Quotation": "Citare",
"Menu:Invoice": "Factură",
"Menu:PaymentRequests": "Solicitări plată",
"Permission:PaymentRequests": "Solicitări plată",
"PaymentRequests": "Solicitări plată",
"Creator": "Creator",
"ExtraProperties": "Proprietăţi extra",
"Organization": "Organizaţia",
"Waiting": "În aşteptare",
"Completed": "Finalizat",
"Failed": "Eşuat",
"PaymentRequestDeletionWarningMessage": "Sunteţi sigur(ă) că doriţi să ştergeţi această plată?",
"Payment": "Plata",
"AddPayment": "Adaugă plată",
"Enum:PurchaseType:1": "Licenţă nouă",
"Enum:PurchaseType:2": "Extindere licenţă",
"Enum:PurchaseType:3": "Îmbunătăţire licenţă",
"Enum:PurchaseType:4": "Dezvoltator suplimentar",
"LicenceType": "Tipul licenţei",
"PurchaseType": "Tipul achiziţiei",
"ReceiptNo": "Chitanţa numărul",
"PaymentTime": "Data plăţii",
"ProductPrice": "Preţul produsului",
"AdditionalDeveloper": "Dezvoltator suplimentar",
"ThisPaymentHasBeenAlreadyUsed": "Această plată a fost deja folosită",
"PaymentTimeCannotBeFutureTime": "Data plăţii nu poate fi în viitor"
}
}

8
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/en.json

@ -35,6 +35,10 @@
"Support": "Support",
"FreeDDDBook": "Free DDD E-book",
"New": "New",
"Volo.AbpIo.Domain:020005": "License extend year can not be lower than {MinExtendLicenseYear} year and greater than {MaxExtendLicenseYear} years "
"Volo.AbpIo.Domain:020005": "License extend year can not be lower than {MinExtendLicenseYear} year(s) and greater than {MaxExtendLicenseYear} year(s) ",
"TrialLicensePeriodHasExpired": "Your trial license period expired {0} days ago.",
"TrialLicensePeriodWillExpire": "Your trial license period will be expired in {0} days.",
"TrialLicensePeriodExpireToday": "Your trial license period will be expired today.",
"PurchaseNow": "Purchase Now!"
}
}
}

40
abp_io/AbpIoLocalization/AbpIoLocalization/Base/Localization/Resources/ro-RO.json

@ -0,0 +1,40 @@
{
"culture": "ro-RO",
"texts": {
"Volo.AbpIo.Domain:010004": "Numărul maxim de membri a fost atins!",
"Volo.AbpIo.Domain:010005": "Numărul maxim de proprietari a fost atins!",
"Volo.AbpIo.Domain:010006": "Există deja un proprietar în această organizaţie!",
"Volo.AbpIo.Domain:010007": "Acest utilizator este deja dezvoltator în această organizaţie!",
"Volo.AbpIo.Domain:010008": "Numărul permis de dezvoltatori nu poate fi mai mic decât numărul curent de dezvoltatori!",
"Volo.AbpIo.Domain:010009": "Numărul permis de dezvoltatori nu poate fi mai mic decât 0!",
"Volo.AbpIo.Domain:010010": "Numărul maxim de adrese de tip mac este depăşit!",
"Volo.AbpIo.Domain:010011": "Licenţa personală nu poate avea mai mult de un dezvoltator!",
"Volo.AbpIo.Domain:010012": "Licenţa nu poate fi prelungită la o lună după ce aceasta a expirat!",
"Volo.AbpIo.Domain:020001": "Nu s-a putut şterge acest pachet NPM deoarece \"{NugetPackages}\" există pachete Nuget dependente de acest pachet.",
"Volo.AbpIo.Domain:020002": "Nu s-a putut şterge acest pachet NPM deoarece \"{Modules}\" modulele folosesc acest pachet.",
"Volo.AbpIo.Domain:020003": "Nu s-a putut şterge acest pachet NPM deoarece \"{Modules}\" modulele folosesc acest pachet \"{NugetPackages}\" şi există pachete Nuget dependente de acest pachet.",
"Volo.AbpIo.Domain:020004": "Nu s-a putut şterge acest pachet Nuget deoarece \"{Modules}\" modulele folosesc acest pachet.",
"WantToLearn?": "Vrei să înveţi?",
"ReadyToGetStarted?": "Eşti gata pentru a începe?",
"JoinOurCommunity": "Alăturaţi-vă comunităţii noastre",
"GetStartedUpper": "ÎNCEPE",
"ForkMeOnGitHub": "Fork me on GitHub",
"Features": "Caracteristici",
"GetStarted": "Începe",
"Documents": "Documente",
"Community": "Comunitate",
"ContributionGuide": "Ghid de contribuţie",
"Blog": "Blog",
"Commercial": "Comercial",
"MyAccount": "Contul meu",
"Permission:License": "Licenţă",
"Permission:UserInfo": "Info utilizator",
"SeeDocuments": "Vezi documente",
"Samples": "Mostre",
"Framework": "Framework",
"Support": "Suport",
"FreeDDDBook": "DDD E-book gratis",
"New": "Nou",
"Volo.AbpIo.Domain:020005": "Anul prelungirii licenţei nu poate fi mai mic decât {MinExtendLicenseYear} şi mai mare decât {MaxExtendLicenseYear}"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Blog/Localization/Resources/ro-RO.json

@ -0,0 +1,5 @@
{
"culture": "ro-RO",
"texts": {
}
}

34
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Dark Blue Theme",
"LightTheme": "Light Theme",
"ProudToWorkWith": "Proud to Work With",
"OurConsumers": "Hundreds of enterprises and developers over 50 countries worldwide rely on ABP Commercial.",
"OurConsumers": "Thousands of enterprises and developers over 70 countries worldwide rely on ABP Commercial.",
"JoinOurConsumers": "Join them and build amazing products fast.",
"AdditionalServicesExplanation": "Do you need additional or custom services? <strong>We and our partners can provide;</strong>",
"CustomProjectDevelopment": "Custom Project Development",
@ -358,6 +358,36 @@
"WeWillSendYouADownloadLink": "A link to download the e-book has been sent to {0}.<br/> Check your inbox / junk / spam boxes!",
"InvalidFormInputs": "Please, type the valid information specified on the form.",
"DDDBookEmailBody": "Thank you. <br /> To download your book, <a href=\"{0}\">click here</a>.",
"FreeDDDEBook": "Free DDD E-Book"
"FreeDDDEBook": "Free DDD E-Book",
"StartFree": "Start free",
"FreeTrial": "Free Trial",
"AcceptsMarketingCommunications": " Yes, I`d like to receive ABP Commercial marketing communications.",
"PurposeOfUsage": "Purpose of usage",
"Industry": "Industry",
"Choose": "- Choose -",
"CompanyOrganizationName": "Company / Organization Name",
"CompanySize": "Company Size",
"Next": "Next",
"StartTrial": "Start My Free Trial",
"ContactUsIssues": "Contact us if you have any issues",
"TrialActivatedWarning": "Dear {0}, a user is entitled to have only 1 free trial period. You already used your trial period.",
"ActivationRequirement": "You are one step away from starting your free trial.<br>We have sent an email to <b>{0}</b> to activate your account. Check your inbox/junk/spam boxes!",
"SaveAndDownload": "Save And Download",
"CompanyNameValidationMessage": "Company name is too long!",
"AddressValidationMessage": "Address is too long!",
"TaxNoValidationMessage": "TAX/VAT No is too long!",
"NotesValidationMessage": "Notes field is too long!",
"CheckYourBillingInfo": "You can create your invoice only once! Check your billing information before creating your invoice.",
"Volo.AbpIo.Commercial:030000": "You already used your trial period.",
"Volo.AbpIo.Commercial:030001": "This organization name already exists.",
"StartYourFreeTrial": "Start your free trial",
"TrialLicenseModelInvalidErrorMessage": "One of the following fields are invalid: Country Name, Company Size, Industry or Purpose Of Usage.",
"Trial": "Trial",
"Purchased": "Purchased",
"PurchaseLicense": "Purchase License",
"PurchaseTrialLicenseMessage": "Your license expiration date is {0}. <br> If you want to continue using the projects you created during your free trial period, you need to change the license keys in your <code>appsettings.secrets.json</code> files. Here is your license key:",
"TrialLicenseExpireMessage": "You are using the trial license and your trial license will expire on {0}.",
"TryForFree": "Try For Free",
"TrialLicenseExpiredInfo": "Your trial license period has expired!"
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fi.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Tummansininen teema",
"LightTheme": "Kevyt teema",
"ProudToWorkWith": "Ylpeä työskennellä",
"OurConsumers": "Sadat yritykset ja kehittäjät yli 50 maassa ympäri maailmaa luottavat ABP Commercialiin.",
"OurConsumers": "Sadat yritykset ja kehittäjät yli 70 maassa ympäri maailmaa luottavat ABP Commercialiin.",
"JoinOurConsumers": "Liity heihin ja rakenna upeita tuotteita nopeasti.",
"AdditionalServicesExplanation": "Tarvitsetko lisä- tai mukautettuja palveluita? <strong> Me ja kumppanimme voimme tarjota; </strong>",
"CustomProjectDevelopment": "Mukautettu projektikehitys",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/fr.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Thème bleu foncé",
"LightTheme": "Thème clair",
"ProudToWorkWith": "Fier de travailler avec",
"OurConsumers": "Des centaines d'entreprises et de développeurs dans plus de 50 pays dans le monde font confiance à ABP Commercial.",
"OurConsumers": "Des centaines d'entreprises et de développeurs dans plus de 70 pays dans le monde font confiance à ABP Commercial.",
"JoinOurConsumers": "Rejoignez-les et créez rapidement des produits incroyables.",
"AdditionalServicesExplanation": "Avez-vous besoin de services supplémentaires ou personnalisés? <strong> Nous et nos partenaires pouvons fournir; </strong>",
"CustomProjectDevelopment": "Développement de projets personnalisés",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/hi.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "डार्क ब्लू थीम",
"LightTheme": "प्रकाश थीम",
"ProudToWorkWith": "गर्व के साथ काम करने के लिए",
"OurConsumers": "दुनिया भर में 50 से अधिक देशों के सैकड़ों उद्यम और डेवलपर्स एबीपी कमर्शियल पर निर्भर हैं।",
"OurConsumers": "दुनिया भर में 70 से अधिक देशों के सैकड़ों उद्यम और डेवलपर्स एबीपी कमर्शियल पर निर्भर हैं।",
"JoinOurConsumers": "उनके साथ जुड़ें और तेजी से अद्भुत उत्पादों का निर्माण करें।",
"AdditionalServicesExplanation": "क्या आपको अतिरिक्त या कस्टम सेवाओं की आवश्यकता है? <strong> हम और हमारे साथी प्रदान कर सकते हैं; </strong>",
"CustomProjectDevelopment": "कस्टम परियोजना विकास",

25
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/it.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Tema blu scuro",
"LightTheme": "Tema chiaro",
"ProudToWorkWith": "Orgoglioso di lavorare con",
"OurConsumers": "Centinaia di aziende e sviluppatori in oltre 50 paesi in tutto il mondo si affidano a ABP Commercial.",
"OurConsumers": "Centinaia di aziende e sviluppatori in oltre 70 paesi in tutto il mondo si affidano a ABP Commercial.",
"JoinOurConsumers": "Unisciti a loro e crea prodotti sorprendenti velocemente.",
"AdditionalServicesExplanation": "Hai bisogno di servizi aggiuntivi o personalizzati? <strong> Noi e i nostri partner possiamo fornire; </strong>",
"CustomProjectDevelopment": "Sviluppo di progetti personalizzati",
@ -358,6 +358,25 @@
"WeWillSendYouADownloadLink": "Un link per scaricare il libro e-book è stato spedito a {0}.<br/> Controlla nella posta in arrivo / indesiderata / spam!",
"InvalidFormInputs": "Per favore, digita le informazioni valide specificate nel modulo",
"DDDBookEmailBody": "Grazie. <br /> Per scaricare il tuo libro, <a href=\"{0}\">clicca qui</a>.",
"FreeDDDEBook": "E-Book Gratuito DDD"
"FreeDDDEBook": "E-Book Gratuito DDD",
"StartFree": "Inizia gratuitamente",
"FreeTrial": "Prova Gratuita",
"AcceptsMarketingCommunications": "Si desidero ricevere comunicazioni marketing riguardanti ABP Commercial",
"PurposeOfUsage": "Proposta di utilizzo",
"Industry": "Settore",
"Choose": "- Scegli -",
"CompanyOrganizationName": "Azienda / Nome organizzazione",
"CompanySize": "Dimensioni Azienda",
"Next": "Prossimo",
"StartTrial": "Inizia la mia prova gratuita",
"ContactUsIssues": "Contattaci per qualsiasi problema",
"TrialActivatedWarning": "Caro {0}, un utente ha diritto di avere 1 solo periodo di prova gratuito. Hai già utilizzato il tuo periodo di prova.",
"ActivationRequirement": "Ti manca un solo passo per iniziare il tuo periodo di prova gratuito.<br>Abbiamo inviato un'email a <b>{0}</b> per attivare il tuo account. Controlla la tua casella di posta e non dimenticare la cartella spam!",
"SaveAndDownload": "Salva e Scarica",
"CompanyNameValidationMessage": "Il nome dell'azienda è troppo lungo!",
"AddressValidationMessage": "L'indirizzo è troppo lungo!",
"TaxNoValidationMessage": "TAX/VAT (IVA) è troppo lungo!",
"NotesValidationMessage": "Il campo note è troppo lungo!",
"CheckYourBillingInfo": "Puoi creare una fattura solo una volta! Controlla i tuoi dati di fatturazione prima di creare una fattura."
}
}
}

363
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/ro-RO.json

@ -0,0 +1,363 @@
{
"culture": "ro-RO",
"texts": {
"OrganizationManagement": "Administrarea organizaţiilor",
"OrganizationList": "Lista organizaţiilor",
"Volo.AbpIo.Commercial:010003": "Nu sunteţi proprietarul acestei organizaţii!",
"OrganizationNotFoundMessage": "Nicio organizaţie găsită!",
"DeveloperCount": "Alocaţi / total dezvoltatori",
"QuestionCount": "Rămase / total întrebări",
"Unlimited": "Nelimitat",
"Owners": "Proprietari",
"AddMember": "Adaugă membru",
"AddOwner": "Adaugă proprietar",
"AddDeveloper": "Adaugă dezvoltator",
"UserName": "Nume utilizator",
"Name": "Nume",
"EmailAddress": "Adresă de email",
"Developers": "Dezvoltatori",
"LicenseType": "Tip licenţă",
"Manage": "Administrează",
"StartDate": "Data de început",
"EndDate": "Data de sfârşit",
"Modules": "Module",
"LicenseExtendMessage": "Data expirării licenţei dumneavoastră a fost prelungită până în {0}",
"LicenseUpgradeMessage": "Licenţa dumneavoastră a fost actualizată la {0}",
"LicenseAddDeveloperMessage": "{0} dezvoltatori au fost ataşaţi licenţei dumneavoastră",
"Volo.AbpIo.Commercial:010004": "Utilizatorul nu a putut fi găsit! Acesta trebuie să se fi înregistrat deja.",
"MyOrganizations": "Organizaţiile mele",
"ApiKey": "Cheie API",
"UserNameNotFound": "Nu există niciun utilizator cu numele {0}",
"SuccessfullyAddedToNewsletter": "Vă mulţumim pentru că v-aţi abonat la newsletter-ul nostru!",
"MyProfile": "Profilul meu",
"EmailNotValid": "Vă rugăm să introduceţi o adresa de email validă.",
"JoinOurMarketingNewsletter": "Alăturaţi-va newsletter-ului nostru de marketing",
"WouldLikeToReceiveMarketingMaterials": "Aş dori să primesc materiale de marketing precum oferte şi oferte speciale.",
"StartUsingYourLicenseNow": "Începe folosirea licenţei tale acum!",
"WelcomePage": "Pagina de bun venit",
"UnsubscriptionExpireEmail": "Dezabonează-te de la emailuri informative despre data expirării licenţei.",
"UnsubscribeLicenseExpireEmailReminderMessage": "Această abonament prin email conţine numai amintirea datei de expirare a licenţei.",
"UnsubscribeFromLicenseExpireEmails": "Dacă nu mai doriţi să primiţi emailuri informative despre data de expirare a licenţei dumneavoastră, puteţi să vă dezabonaţi oricând.",
"Unsubscribe": "Dezabonează-te",
"NotOrganizationMember": "Nu sunteţi membru al niciunei organizaţii.",
"UnsubscribeLicenseExpirationEmailSuccessTitle": "V-aţi dezabonat cu succes.",
"UnsubscribeLicenseExpirationEmailSuccessMessage": "Nu veţi mai primi emailuri informative despre data de expirare a licenţei dumneavoastră.",
"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",
"GetLicence" :"Obţine o licenţă",
"Application": "Application",
"StartupTemplates": "Şabloane de lansare",
"Startup": "Lansare",
"Templates": "Şabloane",
"Developer": "Dezvoltator",
"Tools": "Unelte",
"Premium": "Premium",
"PremiumSupport": "Asistenţă Premium",
"PremiumForumSupport": "Forum asistenţă premium",
"UI": "UI",
"Themes": "Teme",
"JoinOurNewsletter": "Abonaţi-va newsletter-ului nostru",
"Send": "Trimite",
"Learn": "Învaţă",
"AdditionalServices": "Servicii suplimentare",
"WhatIsABPFramework": "CE ESTE FRAMEWORK-UL ABP?",
"OpenSourceBaseFramework": "Open Source Base Framework",
"ABPFrameworkExplanation": "<p class=\"lead\">ABP Commercial se bazează pe framework-ul ABP, un framework open source şi bazat pe comunitate pentru ASP.NET Core.</p><p>ABP Framework oferă o infrastructură excelentă pentru a scrie cod care poate fi întreţinut, extins şi testat cu cele mai bune practici.</p><p>Construit şi integrat în instrumentele populare pe care le cunoaşteţi deja. Curbă de învăţare redusă, adaptare uşoară, dezvoltare confortabilă.</p>",
"Modular": "Modular",
"MicroserviceCompatible": "Compatibil cu microservicii",
"DomainDrivenDesignInfrastructure": "Domain Driven Design Infrastructure",
"MultiTenancy": "Multi-Tenancy",
"DistributedMessaging": "Mesaje distribuite",
"DynamicProxying": "Proxy dinamic",
"BackgroundJobs": "Background Jobs",
"AuditLogging": "Înregistrarea auditului",
"BLOBStoring": "BLOB Storing",
"BundlingMinification": "Bundling & Minification",
"AdvancedLocalization": "Localizare avansată",
"ManyMore": "Multe altele",
"ExploreTheABPFramework": "Exploraţi framework-ul ABP",
"WhyUseTheABPCommercial": "De ce să folosiţi ABP Commercial?",
"WhyUseTheABPCommercialExplanation": "<p class=\"lead mt- 5\">Construirea de aplicaţii web de nivel enterprise poate fi complexă şi poate consuma mult timp.</p><p>ABP Commercial oferă infrastructura de bază pentru toate soluţiile moderne bazate pe ASP.NET Core de nivel enterprise. De la proiectare până la implementare, întregul ciclu de dezvoltare este împuternicit de funcţiile şi modulele integrate ale ABP.</p>",
"StartupTemplatesShortDescription": "Şabloanele de pornire vă fac să începeţi proiectul în câteva secunde.",
"UIFrameworksOptions": "UI frameworks options;",
"DatabaseProviderOptions": "Opţiuni furnizor de bază de date;",
"PreBuiltApplicationModules": "Module de aplicaţii pre-construite",
"PreBuiltApplicationModulesShortDescription": "Cele mai comune cerinţe de aplicaţie sunt deja dezvoltate pentru dumneavoastră sub formă de module reutilizabile.",
"Account": "Cont",
"Blogging": "Blogging",
"Identity": "Identitate",
"IdentityServer": "Identity Server",
"Saas": "Saas",
"LanguageManagement": "Administrarea limbilor",
"TextTemplateManagement": "Text Template Management",
"SeeAllModules": "Vezi toate modulele",
"ABPSuite": "ABP Suite",
"AbpSuiteShortDescription": "ABP Suite este un instrument complementar pentru ABP Commercial.",
"AbpSuiteExplanation": "Vă permite să creaţi pagini web în câteva minute. Este un instrument .NET Core global, care poate fi instalat din linia de comandă. Poate crea o nouă soluţie ABP, poate genera pagini CRUD, începând de la baza de date până la front-end.",
"Details": "Detalii",
"LeptonTheme": "Tema Lepton",
"ProfessionalModernUIThemes": "Teme UI profesionale, moderne",
"LeptonThemeExplanation": "Lepton oferă o gamă de teme de administrare Bootstrap, care servesc ca o bază solidă pentru orice proiect care necesită tabloul de bord de administrare.",
"DefaultTheme": "Tema Default",
"MaterialTheme": "Tema Material",
"Default2Theme": "Tema Default 2",
"DarkTheme": "Tema Dark",
"DarkBlueTheme": "Tema Dark Blue",
"LightTheme": "Tema Light",
"ProudToWorkWith": "Mândru să lucrez cu",
"OurConsumers": "Sute de întreprinderi şi dezvoltatori din peste 70 de ţări din jurul lumii se bazează pe ABP Commercial.",
"JoinOurConsumers": "Alăturaţi-va lor şi construiţi produse uimitoare rapid.",
"AdditionalServicesExplanation": "Aveţi nevoie de servicii suplimentare sau personalizate? <strong>Noi şi partenerii noştri vi le putem oferi;</strong>",
"CustomProjectDevelopment": "Custom Project Development",
"CustomProjectDevelopmentExplanation": "Dezvoltatori dedicaţi pentru proiectele dumneavoastră personalizate.",
"PortingExistingProjects": "Portarea proiectelor existente",
"PortingExistingProjectsExplanation": "Migrarea proiectelor dumneavoastră vechi pe platforma ABP.",
"LiveSupport": "Asistenţă live",
"LiveSupportExplanation": "Opţiune de asistenţă live la distanţă oricând aveţi nevoie.",
"Training": "Instruire",
"TrainingExplanation": "Instruire dedicată pentru dezvoltatorii dumneavoastră.",
"OnBoarding": "Integrare",
"OnBoardingExplanation": "Ajutor pentru configurarea dezvoltării, mediilor CI & CD.",
"PrioritizedTechnicalSupport": "Asistenţă tehnică prioritară",
"PremiumSupportExplanation": "Pe lângă excelentul suport comunitar al framework-ului ABP, echipa noastră de asistenţă răspunde la întrebările tehnice şi la problemele utilizatorilor comerciali cu prioritate crescută.",
"SeeTheSupportOptions": "Vedeţi opţiunile de asistenţă",
"Contact": "Contact",
"TellUsWhatYouNeed": "Spuneţi-ne de ce aveţi nevoie.",
"YourMessage": "Mesajul dumneavoastră",
"YourFullName": "Numele dumneavoastră complet",
"EmailField": "Adresa de email",
"YourEmailAddress": "Adresa dumneavoastră de email",
"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",
"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",
"ApplicationTemplateExplanation": "Şablonul de pornire a aplicaţiei este utilizat pentru a crea o nouă aplicaţie web.",
"EfCoreProvider": "Entity Framework (susţine SQL Server, MySQL, PostgreSQL, Oracle <a href=\"https://docs.microsoft.com/en-us/ef/core/providers/\">şi altele</a>)",
"AlreadyIncludedInTemplateModules": "Următoarele module sunt deja incluse şi configurate în acest şablon:",
"ApplicationTemplateArchitecture": "Acest şablon de aplicaţie susţine arhitecturi structurate pe nivele, în care nivelul UI, nivelul API şi serviciul de autentificare sunt separate fizic.",
"SeeTheGuideOrGoToTheLiveDemo": "Consultaţi ghidul dezvoltatorului pentru informaţii tehnice despre acest şablon sau mergeţi la demo-ul live.",
"DeveloperGuide": "Ghidul dezvoltatorului",
"ModuleTemplate": "Module Template",
"ModuleTemplateExplanation1": "Vreţi să creaţi un modul pe care sa-l reutilizaţi în cadrul diferitelor aplicaţii? Acest şablon de pornire pregăteşte totul pentru a putea începe să creaţi un <strong>modul</strong> sau un <strong>microserviciu</strong> reutilizabil.",
"ModuleTemplateExplanation2": "<p>Puteţi susţine cadre UI simple sau multiple, furnizori unici sau multipli pentru baza de date pentru un singur modul. Şablonul de pornire este configurat pentru a rula <strong>şi testa modulul dumneavoastră</strong> într-o aplicaţie minimă, în plus faţă de infrastructura de testare şi integrare.</p> <p>Consultaţi ghidul dezvoltatorului pentru informaţii tehnice despre acest şablon.</p>",
"WithAllStyleOptions": "cu toate opţiunile de stil",
"Demo": "Demo",
"SeeAllModules": "Vezi toate modulele",
"ABPCLIExplanation": "ABP CLI (Command Line Interface) este un instrument de linii de comandă pentru executarea unor operaţii comune pentru soluţiile ABP.",
"ABPSuiteEasilyCURD": "Suita ABP este un instrument care vă permite crearea cu uşurinţă a paginilor CRUD",
"WeAreHereToHelp": "Suntem aici să <span class=\"zero-text\">Ajutăm</span>",
"BrowseOrAskQuestion": "Puteţi răsfoi subiectele noastre de ajutor sau puteţi căuta în cadrul secţiunii întrebărilor frecvent adresate, sau ne puteţi adresa o întrebare folosind <a href=\"{0}\" class=\"text-success\">formularul de contact</a>.",
"SearchQuestionPlaceholder": "Caută în întrebările frecvent adresate",
"WhatIsTheABPCommercial": "Ce este ABP Commercial?",
"WhatAreDifferencesThanAbpFramework": "Care sunt diferenţele dintre ABP Framework şi ABP Comercial?",
"ABPCommercialExplanation": "ABP Commercial este un set de module premium, instrumente, teme şi servicii construite pe baza <a target=\"_blank\" href=\"{0}\">ABP framework</a>. ABP Commercial este dezvoltat şi întreţinut de către aceeaşi echipă din spatele ABP framework.",
"WhatAreDifferencesThanABPFrameworkExplanation": "<p> <a target=\"_blank\" href=\"{0}\">ABP framework</a> este un framework de dezvoltare de aplicaţii modulare, compatibil cu micro-servicii dedicate ASP.NET Core. Oferă o arhitectură completă şi o infrastructură puternică pentru a vă face să vă concentraţi asupra propriului cod, mai degrabă decât să vă repetaţi pentru fiecare proiect nou. Se bazează pe cele mai bune practici de dezvoltare software, şi pe instrumentele populare pe care le cunoaşteţi deja. </p><p>ABP Framework este complet gratuit, open-source şi bazat pe comunitate. De asemenea, oferă şi o temă gratuită şi câteva module pre-construite (de exemplu, gestionarea identităţii şi a chiriaşilor).</p>",
"VisitTheFrameworkVSCommercialDocument": "Accesaţi următorul link, pentru mai multe informaţii <a href=\"{0}\" target=\"_blank\"> {1} </a>",
"ABPCommercialFollowingBenefits": "ABP Commercial adaugă următoarele beneficii peste framework-ul ABP;",
"Professional": "Profesional",
"UIThemes": "Teme UI",
"EnterpriseModules": "<a href=\"{0}\">Module de aplicaţii</a> pregătite pentru întreprinderi, bogate în funcţionalităţi, pre-construite (e.g. Identity Server management, SaaS management, language management)",
"ToolingToSupport": "Instrumente pentru a vă susţine productivitatea de dezvoltare (e.g. <a href=\"{0}\">Suita ABP</a>)",
"PremiumSupportLink": "<a href=\"{0}\" target=\"_blank\">Asistenţă</a> premium",
"WhatDoIDownloadABPCommercial": "Ce descarc când cumpăr ABP Commercial?",
"CreateUnlimitedSolutions": "Odată ce aţi cumpărat o licenţă ABP Commercial, veţi putea să creaţi soluţii nelimitate, descrise în documentul <a href=\"{0}\">Noţiuni de bază</a>.",
"ABPCommercialSolutionExplanation": "Când creaţi o aplicaţie nouă, veţi primi o soluţie de Visual Studio (un şablon de pornire) bazat pe preferinţele dumneavoastră. Soluţia descărcată conţine module comerciale şi teme pre-instalate şi configurate pentru dumneavoastră. Puteţi şterge un modul pre-instalat sau să adăugaţi altul dacă doriţi. Toate modulele şi temele folosesc un pachet NuGet/NPM în mod implicit.",
"StartDevelopWithTutorials": "Soluţia descărcată este bine structurată şi documentată. Puteţi începe să vă dezvoltaţi codul dumneavoastră pe baza unuia dintre <a href=\"{0}\">tutoriale</a>",
"TryTheCommercialDemo": "Puteţi încerca versiunea <a href=\"{0}\">demo</a> pentru a vedea un exemplu de aplicaţie creată folosind şablonul de pornire ABP Commercial.",
"HowManyProducts": "Câte produse/soluţii diferite pot construi folosind ABP Commercial?",
"HowManyProductsExplanation": "Nu există nicio limită pentru crearea unui proiect ABP. Puteţi crea cât de multe proiecte doriţi, pe care să le dezvoltaţi sau încărcaţi pe diferite servere.",
"HowManyDevelopers": "Câţi dezvoltatori pot lucra pe ABP Commercial?",
"HowManyDevelopersExplanation": "Licenţele de ABP Commercial sunt per dezvoltator. Tipuri diferite de licenţă au limite diferite de dezvoltatori. Totuşi, puteţi ataşa mai mulţi dezvoltatori unei licenţe oricând doriţi. Consultaţi <a href=\"{0}\">preţurile</a> pentru tipurile de licenţă, limitele de dezvoltatori şi costurile adiţionale pentru dezvoltatori.",
"ChangingLicenseType": "Pe viitor pot să schimb tipul licenţei?",
"ChangingLicenseTypeExplanation": "Puteţi adăuga oricând noi dezvoltatori în licenţa dumneavoastră de acelaşi tip. Consultaţi \"Câţi dezvoltatori pot lucra pe ABP Commercial?\". De asemenea, puteţi opta pentru o licenţă superioară prin plătirea achitarea de preţ. Atunci când optaţi pentru o licenţă superioară, veţi avea parte de beneficiile noii licenţe, însă acest lucru nu va schimba data expirării licenţei.",
"LicenseExtendUpgradeDiff": "Care este diferenţa dintre prelungirea licenţei şi îmbunătăţirea acesteia?",
"LicenseExtendUpgradeDiffExplanation": "<strong>Prelungirea:</strong> Prin prelungirea/reînnoirea licenţei dumneavoastră, veţi continua să aveţi acces la asistenţă premium, şi veţi avea parte de actualizările majore ale modulelor şi temelor. Pe lângă asta, veţi putea în continuare să creaţi proiecte noi. Veţi putea folosi în continuare suita ABP, ceea ce va accelera dezvoltarea.<hr/><strong>Îmbunătăţirea:</strong> Prin îmbunătăţirea licenţei dumneavoastră, veţi promova la un plan de licenţă superior, care vă va permite să beneficiaţi de anumite avantaje. Consultaţi <a href=\"/pricing\">tabelul de comparare a licenţelor</a> pentru a verifica diferenţele dintre planurile de licenţă.<strong>Pe de altă parte, când îmbunătăţiţi licenţa, data de expirare a acesteia nu se va schimba!</strong>Pentru a vă extinde data de încheiere a licenţei, va trebui să vă extindeţi licenţa.",
"LicenseRenewalCost": "Care este costul de reînnoire a licenţei dupa 1 an?",
"LicenseRenewalCostExplanation": "Rata de reînnoire (extindere) a tuturor licenţelor ABP Comercial reprezintă {0} din preţul listei licenţelor. Preţul de reînnoire a licenţei standard de echipă este de ${1}, cel pentru licenţa standard de afaceri este de ${2} iar cel pentru licenţa standard enterprise este de ${3}. Dacă deja sunteţi clientul nostru, <a href='{4}' target='_blank'>autentificaţi-vă</a> pentru a examina preţurile disponibile pentru reînnoire.",
"HowDoIRenewMyLicense": "Cum îmi reînnoiesc licenţa?",
"HowDoIRenewMyLicenseExplanation": "Puteţi să vă reînnoiţi licenţa prin accesarea paginii <a href='{0}' target='_blank'>pagina de gestionare a organizaţiei</a>. Pentru a profita de tarifele noastre reduse de reînnoire anticipată, asiguraţi-vă că reînnoiţi înainte de expirarea licenţei. Totuşi, nu vă faceţi griji dacă nu ştiţi când expiră oportunitatea dumneavoastră de reînnoire anticipată. Veţi primi 2 e-mailuri de reamintire înainte de expirarea abonamentului. Vi le vom trimite cu 30, respectiv 7 zile înainte de expirare.",
"IsSourceCodeIncluded": "Licenţa mea include şi codul sursă al modulelor comerciale şi a temelor?",
"IsSourceCodeIncludedExplanation1": "Depinde de tipul de licenţă pe care aţi achiziţionat-o:",
"IsSourceCodeIncludedExplanation2": "<strong>Team</strong>: Soluţia dumneavoastră foloseste modulele şi temele sub formă de pachete NuGet şi NPM. Nu include şi codul lor sursă. În acest mod, puteţi cu uşurinţă să îmbunătăţiţi aceste module şi teme oricând este o nouă versiune disponibilă. Totuşi, nu veţi primi codul sursă al modulelor şi temelor.",
"IsSourceCodeIncludedExplanation3": "<strong>Business/Enterprise</strong>: Pe lângă licenţa de tip Team, veţi putea să descărcaţi codul sursă al oricărui modul sau al oricărei teme doriţi. Puteţi chiar să eliminaţi referinţele pachetelor NuGet/NPM pentru un anume modul, şi să adăugaţi codul sursă al acestuia direct în soluţia dumneavoastră pentru a-l putea modifica pe deplin.",
"IsSourceCodeIncludedExplanation4": "<p>Includerea codului sursă al unui modul în soluţia dumneavoastră vă oferă libertate maximă de a personaliza modulul respectiv. Totuşi, atunci nu va fi posibilă actualizarea automată a modulului atunci când o nouă versiune este publicată.</p><p>Niciuna dintre licenţe nu include codul sursă al suitei ABP, care este un instrument extern care generează cod pentru dumneavoastră şi contribuie la dezvoltare.</p><p>Consultaţi <a href=\"{0}\">preţurile</a> pentru alte diferenţe între tipurile de licenţe.</p>",
"ChangingDevelopers": "Pe viitor, pot schimba dezvoltatorii ataşaţi organizaţiei mele?",
"ChangingDevelopersExplanation": "În plus faţă de adăugarea de noi dezvoltatori la licenţa dumneavoastră, puteţi schimba şi dezvoltatorii existenţi(puteţi elimina un dezvoltator şi adăuga unul nou în locul lui) fără costuri suplimentare.",
"WhatHappensWhenLicenseEnds": "Ce se întâmplă când se încheie perioada licenţei mele?",
"WhatHappensWhenLicenseEndsExplanation1": "Tipul de licenţă ABP Comercial este o <a href=\"{0}\" target=\"_blank\">licenţă perpetuă</a>. După ce vă expiră licenţa, puteţi continua dezvoltarea proiectului dumneavoastră. Şi nu sunteţi obligat să vă reînnoiţi licenţa. Licenţa dumneavoastră vine la pachet cu actualizări şi plan de asistenţă valabile timp de un an. Pentru a continua să beneficiaţi de noi caracteristici, îmbunătăţiri de performanţe, corectarea erorilor, asistenţă şi să continuaţi să utilizaţi suita ABP, asiguraţi-vă că vă reînnoiţi licenţa anual. Când vă expiră licenţa, nu veţi mai beneficia de niciunul din beneficiile următoare;",
"WhatHappensWhenLicenseEndsExplanation2": "Nu puteţi crea noi soluţii folosind ABP Commercial, dar puteţi continua dezvoltarea aplicaţiilor existente oricând.",
"WhatHappensWhenLicenseEndsExplanation3": "You will be able to get updates for the modules and themes within your MAJOR version. For example; if you are using v3.2.0 of a module, you can still get updates for v3.x.x (v3.3.0, v3.5.2... etc.) of that module. But you cannot get updates for the next major version (like v4.x, v5.x)",
"WhatHappensWhenLicenseEndsExplanation4": "Nu puteţi instala noi module şi teme adăugate pe platforma ABP Comercial după ce se încheie licenţa dumneavoastră.",
"WhatHappensWhenLicenseEndsExplanation5": "Nu puteţi folosi suita ABP.",
"WhatHappensWhenLicenseEndsExplanation6": "Nu veţi mai avea parte de <a href=\"{0}\">asistenţă premium</a>.",
"WhatHappensWhenLicenseEndsExplanation7": "Puteţi să vă reînnoiţi abonamentul dacă vreţi să continuaţi să aveţi parte de aceste beneficii. Dacă vă reînnoiţi abonamentul în termen de o lună după ce vă expiră licenţa, vi se aplică un discount de 20%.",
"WhenShouldIRenewMyLicense": "Când ar trebui să-mi reînnoiesc licenţa?",
"WhenShouldIRenewMyLicenseExplanation1": "Dacă vă reînnoiţi licenţa în termen de <strong>1 lună</strong> după ce vă expiră licenţa, se va aplica un discount de 20%.",
"WhenShouldIRenewMyLicenseExplanation2": "Dacă vă reînnoiţi licenţa la o lună după ce aceasta a expirat, preţul de reînnoire va fi acelaşi cu cel iniţial, şi nu va fi aplicat niciun discount pentru reînnoirea dumneavoastră.",
"TrialPlan": "Aveţi un plan de încercare?",
"TrialPlanExplanation": "Pentru moment, ABP Comercial nu include un plan de încercare. Pentru licenţa de Team oferim înapoirea banilor în termen de 30 de zile. Puteţi să solicitaţi o restituire în primele 30 de zile. Pentru licenţele de tip Business şi Enterprise, noi asigurăm restituirea a 60% din sumă în 30 de zile. Acest lucru se datorează faptului că licenţele de tip Business şi Enterprise includ codul sursă complet al tuturor modulelor şi temelor.",
"DoYouAcceptBankWireTransfer": "Acceptaţi transfer bancar?",
"DoYouAcceptBankWireTransferExplanation": "Da, acceptăm transfer bancar.<br />După trimiterea taxei de licenţă prin transfer bancar, trimiteţi-ne pe e-mail la info@abp.io chitanţa dumneavoastră şi tipul de licenţă solicitat. Informaţiile despre contul bancar internaţional al nostru:",
"HowToUpgrade": "Cum se actualizează aplicaţiile existente atunci când este disponibilă o nouă versiune?",
"HowToUpgradeExplanation1": "Cand creaţi o nouă aplicaţie folosind ABP Commercial, toate modulele şi tema sunt folosite sub formă de pachete NuGet şi NPM. Astfel, puteţi cu uşurinţă să actualizaţi pachetele atunci când o versiune nouă este disponibilă.",
"HowToUpgradeExplanation2": "Pe lângă actualizările standard NuGet-NPM, <a href=\"{0}\">ABP CLI</a> furnizează o comandă de actualizare automată care identifică şi actualizează toate pachetele legate de ABP din soluţia dumneavoastră.",
"DatabaseSupport": "Ce sisteme de baze de date sunt suportate?",
"DatabaseSupportExplanation": "ABP Framework în sine este agnostic din punct de vedere al bazei de date, şi poate funcţiona cu orice furnizor de baze de date prin natura sa. Consultaţi <a href=\"{0}\" target=\"_blank\">documentul de acces la date</a> pentru o listă a furnizorilor implementaţi până în clipa de faţă.",
"UISupport": "Ce UI frameworks sunt suportate?",
"Supported": "Suportat",
"UISupportExplanation": "ABP Framework în sine este agnostic din punct de vedere al UI framework şi poate funcţiona cu orice UI framework. Cu toate acestea, şabloanele de pornire, UI-urile modulelor şi temele nu au fost implementate pentru toate module UIs. Consultaţi <a href=\"{0}\">documentul de început</a> pentru lista actualizată a opţiunilor UI.",
"MicroserviceSupport": "Suportă arhitectura de micro-servicii?",
"MicroserviceSupportExplanation1": "Unul din scopurile principale ale ABP framework este să furnizeze o structură convenabilă pentru crearea soluţiilor micro-service. Consultaţi documentul <a href=\"{0}\">arhitectura micro-service</a> pentru a înţelege cum ajută la crearea sistemelor de micro-servicii.",
"MicroserviceSupportExplanation2": "Toate modulele ABP Commercial sunt dezvoltate pentru a suporta scenarii de implementare a micro-serviciilor (cu propriul API şi bază de date) prin respectarea <a href=\"{0}\">celor mai bune practici de dezvoltare a modulelor</a>.",
"MicroserviceSupportExplanation3": "Vă oferim <a href=\"{0}\">soluţie demo de micro-servicii</a> care demonstrează o implementare a arhitecturii de micro-servicii pentru a vă ajuta să vă creaţi propria soluţie.",
"MicroserviceSupportExplanation4": "Deci, răspunsul pe scurt este \"<strong>da, suportă o arhitectură de micro-service</strong>\".",
"MicroserviceSupportExplanation5": "Totuşi, un sistem de tip micro-service reprezintă o soluţie, şi fiecare soluţie va avea cerinţe diferite, topologie de reţea, scenarii de comunicare, posibilităţi de autentificare, separarea bazei de date/împărţirea deciziilor, configurări în timp real, integrări de sisteme terţe parte şi multe altele.",
"MicroserviceSupportExplanation6": "ABP Framework şi ABP Commercial furnizează infrastructura pentru scenarii de micro-servicii, module de micro-servicii compatibile, exemple şi documentaţie pentru a vă ajuta să vă construiţi propria soluţie. Dar nu vă aşteptaţi să descărcaţi direct soluţia visurilor dumneavoastră. Veţi fi nevoit(ă) să o întelegeţi şi să puneţi câteva piese cap la cap pe baza cerinţelor dumneavoastră.",
"WhereCanIDownloadSourceCode": "De unde pot descărca codul sursă?",
"WhereCanIDownloadSourceCodeExplanation": "Puteţi descărca codul sursă al tuturor modulelor ABP, pachetelor Angular şi al temelor prin suita ABP sau ABP CLI. Consultaţi <a href=\"{0}\">Cum descarc codul sursă?</a>",
"ComputerLimitation": "Pe câte calculatoare se poate autentifica un dezvoltator atunci când foloseşte ABP ABP?",
"ComputerLimitationExplanation": "Permitem în mod specific <strong>{0} staţii</strong> per dezvoltator individual/autorizat. Ori de câte ori este nevoie ca un dezvoltator să dezvolte produse ABP Commercial pe o altă staţie, un e-mail ar trebui să fie trimis la license@abp.io pentru a explica situaţia, şi atunci vom face alocarea corespunzătoare în sistemul nostru.",
"RefundPolicy": "Aveţi o politică de rambursare?",
"RefundPolicyExplanation": "Puteţi solicita un ramburs în decurs de <strong>30 de zile</strong> de la cumpărarea licenţei. Licenţele de tip Business şi Enterprise au opţiune de descărcare a codului sursă, prin urmare rambursul nu este posibil pentru licenţele Business and Enterprise (şi pentru oricare altă licenţă care beneficiază de dreptul de a primi codul sursă). În plus, nu se fac rambursări pentru reînnoiri şi achiziţii de licenţe suplimentare.",
"HowCanIRefundVat": "Cum pot deduce TVA-ul?",
"HowCanIRefundVatExplanation1": "Dacă aţi făcut plata folosind 2Checkout, puteţi deduce TVA-ul în contul dumneavoastră 2Checkout:",
"HowCanIRefundVatExplanation2": "Autentificaţi-vă în contul dumneavoastră <a href=\"https://secure.2checkout.com/cpanel/login.php\" target=\"_blank\">2Checkout</a>",
"HowCanIRefundVatExplanation3": "Găsiţi comanda respectivă şi apăsaţi pe \"Deducerea tardivă a TVA-ului \" (introduceţi CUI-ul dumneavoastră)",
"HowCanIGetMyInvoice": "Cum îmi pot obţine factura?",
"HowCanIGetMyInvoiceExplanation": "Există două procesatori de plăţi pentru cumpărarea unei licenţă: PayU şi 2Checkout. Dacă veţi cumpăra o licenţă prin procesatorul 2Checkout, vă va trimite chitanţa PDF pe adresa dumneavoastră de email, consultaţi <a href=\"https://knowledgecenter.2checkout.com/Documentation/03Billing-and-payments/Payment-operations/How-do-invoices-work\">facturarea 2Checkout.</a> Dacă veţi cumpăra o licenţă prin procesatorul PayU gateway sau prin transfer bancar, vă vom pregăti chitanţa şi vă vom trimite. Puteţi solicita chitanţa dumneavoastră din <a href=\"{0}\">pagina de gestionare a organizaţiei.</a>",
"Forum": "Forum",
"SupportExplanation": "Licenţele ABP Commercial furnizează asistenţă premium pe forum din partea unei echipe alcătuite din experţi ai ABP.",
"PrivateTicket": "Tichet privat",
"PrivateTicketExplanation": "Licenţa de tip Enterprise include de asemenea şi asistenţă privată cu sisteme de e-mail şi tichete.",
"AbpSuiteExplanation1": "Suita ABP vă permite să construiţi pagini web în decurs de câteva minute. Este un instrument global .NET Core care poate fi instalat din linia de comandă.",
"AbpSuiteExplanation2": "Poate crea o nouă soluţie ABP, genera paginii CRUD începând de la baza de date şi până la front-end. Pentru o prezentare tehnică consultaţi <a href=\"{0}\">documentul</a>",
"FastEasy": "Rapid şi usor",
"AbpSuiteExplanation3": "Suita ABP vă permite să creaţi pagini CRUD cu uşurinţă. Trebuie doar să vă definiţi entitatea şi proprietăţile sale, şi să lăsaţi restul în seama suitei ABP! Suita ABP generează tot codul necesar pentru pagina dumneavoastră CRUD în câteva secunde. Suportă interfeţe de utilizator Angular, MVC şi Blazor.",
"RichOptions": "Opţiuni ample",
"AbpSuiteExplanation4": "Suita ABP suportă multiple opţiuni UI precum <a href=\"https://docs.microsoft.com/en-us/aspnet/core/razor-pages\">Pagini Razor</a> şi <a href=\"https://angular.io\">Angular</a>. Suportă de asemenea şi baze de date multiple, precum <a href=\"https://www.mongodb.com\">MongoDB</a> şi toate bazele de date suportate de <strong>EntityFramework Core</strong> (MS SQL Server, Oracle, MySql, PostgreSQL şi <a href=\"https://docs.microsoft.com/en-us/ef/core/providers/?tabs=dotnet-core-cli\">altele</a>).",
"AbpSuiteExplanation5": "Partea bună este că dumneavoastră nu trebuie să vă faceţi griji despre aceste opţiuni. Suita ABP înţelege tipul proiectului dumneavoastră şi generează cod pentru proiectul dumneavoastră şi îl plasează în locul potrivit din proiect.",
"SourceCode": "Cod sursă",
"AbpSuiteExplanation6": "Suita ABP generează codul sursă pentru dumneavoastră! Nu generează fişiere magice pentru a genera pagina web. Suita ABP generează codul sursă petnru <strong>Entity, Repository, Application Service, Code First Migration, JavaScript/TypeScript şi CSHTML/HTML</strong> şi interfeţele necesare de asemenea. Suita ABP generează de asemenea codul respectând <strong>Cele mai bune practici</strong> ale dezvoltării software, deci nu trebuie să vă faceţi griji în legătură cu calitatea codului generat.",
"AbpSuiteExplanation7": "Deoarece aveţi codul sursă al blocurilor de construcţie ale paginii CRUD generate în straturile de aplicaţie corecte, puteţi modifica cu uşurinţă codul sursă şi puteţi injecta logica personalizată/business a codului generat.",
"CrossPlatform": "Platformă transversală",
"AbpSuiteExplanation8": "Suita ABP este construită cu .NET Core şi este o platformă transversală. Se execută ca o aplicaţie web pe calculatorul dumneavoastră local. O puteţi rula pe <strong>Windows</strong>, <strong>Mac</strong> şi <strong>Linux</strong>",
"OtherFeatures": "Alte funcţionalităţi",
"OtherFeatures1": "Actualizeată pachetele <strong>NuGet</strong> şi <strong>NPM</strong> din soluţia dumneavoastră cu uşurinţă.",
"OtherFeatures2": "Regenerează paginile deja generate de la zero.",
"OtherFeatures3": "Crează noi soluţii",
"ThanksForCreatingProject": "Mulţumim pentru că v-aţi creat proiectul!",
"HotToRunSolution": "Cum să rulaţi soluţia dumneavoastră?",
"HotToRunSolutionExplanation": "Consultaţi documentul de noţiuni de bază pentru a învăţa cum să vă configuraţi şi rulaţi aplicaţia.",
"GettingStarted": "Noţiuni de bază",
"WebAppDevTutorial": "Tutorial Web App Dev",
"WebAppDevTutorialExplanation": "Consultaţi tutorialul de dezvoltare a aplicaţiilor web pentru un exemplu de dezvoltare pas cu pas.",
"Document": "Document",
"UsingABPSuiteToCURD": "Folosind suita ABp pentru generarea şi utilizarea paginilor CRUD",
"SeeABPSuiteDocument": "Consultaţi documentaţia suitei ABP pentru a învăţa utilizarea suitei ABP.",
"AskQuestionsOnSupport": "Puteţi adresa întrebări pe ABP Commercial Support.",
"Documentation": "Documentaţie",
"SeeModulesDocument": "Consultaţi documentul modulelor pentru lista tuturor modulelor comerciale (pro) şi documentele acestora.",
"Pricing": "Preţuri",
"PricingExplanation": "Alegeţi caracteristicile şi funcţionalitatea nevoilor afacerii dumneavoastră acum. Actualizaţi-le cu uşurinţă pe măsură ce afacerea dumneavoastră se dezvoltă.",
"Team": "Team",
"Business": "Business",
"Enterprise": "Enterprise",
"Custom": "Personalizat",
"IncludedDeveloperLicenses": "Licenţe de dezvoltator incluse",
"CustomLicenceOrAdditionalServices": "Aveţi nevoie de o licenţă personalizată sau de servicii suplimentare?",
"CustomOrVolumeLicense": "Licenţă personalizată sau de volum",
"LiveTrainingSupport": "Instruire şi asistenţă în timp real",
"AndMore": "şi multe altele",
"AdditionalDeveloperLicense": "Licenţă suplimentară de dezvoltator",
"ProjectCount": "Număr de proiecte",
"AllProModules": "Toate modulele pro",
"AllProThemes": "Toate temele pro",
"AllProStartupTemplates": "Toate şabloanele de pornire pro",
"SourceCodeOfAllModules": "Codul sursă al tuturor modulelor",
"SourceCodeOfAllThemes": "Codul sursă al tuturor temelor",
"PerpetualLicense": "Licenţă perpetuă",
"UnlimitedServerDeployment": "Implementări nelimitate a serverului",
"YearUpgrade": "actualizare de 1 an",
"YearPremiumForumSupport": "Asistenţă premium pe forum de 1 an",
"ForumSupportIncidentCountYear": "Asistenţă pe forum număr de incidente/an",
"PrivateTicketEmailSupport": "Tichet privat şi asistenţă pe email",
"BuyNow": "Cumpără acum",
"PayViaAmexCard": "Cum pot plăti folosind cardul meu AMEX?",
"PayViaAmexCardDescription": "Procesatorul implicit 'Iyzico' s-ar putea să refuze anumite carduri AMEX ca măsură de securitate. În acest caz, puteţi plăti prin procesatorul alternativ '2Checkout'.",
"ThankYou": "Vă mulţumim",
"InvalidReCaptchaErrorMessage": "A intervenit o eroare în verificarea reCAPTCHA. Vă rugăm să încercaţi din nou.",
"CompanyName": "Nume companie",
"YourCompanyName": "Numele companiei dumneavoastră",
"FirstName": "Nume",
"LastName": "Prenume",
"Optional": "Opţional",
"YourFirstName": "Numele dumneavoastră",
"YourLastName": "Prenumele dumneavoastră",
"SpecialOffer": "Ofertă specială",
"SpecialOfferMessage": "Grăbiţi-vă! Preţurile sunt disponibile pentru o perioadă limitată.",
"DiscountRequest": "Cerere de discount",
"DiscountRequestDescribeCustomerQuestion": "Care din următoarele vă descrie?",
"DiscountRequestStudentEmailMessage": "Adresa de email trebuie să conţină 'edu'.",
"DiscountRequestDeveloperCount": "Câţi dezvoltatori aveţi?",
"DiscountRequestDeveloperCountExceedMessage": "Nu furnizăm licenţe reduse pentru companii care au peste {0} dezvoltatori.",
"DiscountRequestOrganizationName": "Numele companiei/organizaţiei/şcolii",
"Website": "Site web",
"GithubUsername": "Nume de utilizator GitHub",
"PhoneNumber": "Număr de telefon",
"Country": "Ţara",
"DescribeABPCommercialUsage": "Descrieţi proiectul pe care folosiţi să-l dezvoltaţi pe baza APB Commercial",
"DiscountRequestCertifyInformationMessage": "Certific că toate informaţiile sunt adevărate şi corecte.",
"DiscountRequestReceived": "Am primit solicitarea dumneavoastră de reducere.",
"DiscountRequestStatusMessage": "Vă vom răspunde după verificarea informaţiilor pe care le-aţi furnizat.",
"MVCOrRazorPages": "MVC (Razor Pages)",
"Angular": "Angular",
"Blazor": "Blazor",
"New": "New",
"MongoDB": "MongoDB",
"EBookDDD": "E-Book Domain Driven Design",
"PracticalGuideForImplementingDDD": "Această carte reprezintă un ghid practic pentru implementarea proiectării bazate pe domeniu în ABP Framework.",
"IntroducingDDD": "Introducing Domain Driven Design",
"DDDLayersAndCleanArchitecture": "DDD Layers & Clean Architecture",
"LayeringOfADotnetSolution": "Layering of a .NET Solution",
"ImplementingDDDBuildingBlocks": "Implementing DDD Building Blocks",
"DomainVsApplicationLogic": "Domain Logic vs Application Logic",
"SamplesAndDiscussions": "Exemple & Discuţii",
"Free": "Gratuit",
"Download": "Descarcă",
"DDDEBook": "DDD E-book",
"ImplementingDDD": "Implementing Domain Driven Design",
"DDDBookExplanation": "Ghid practic pentru implementarea proiectării bazate pe domeniu în ABP Framework.",
"Overview": "Prezentare generală",
"DDDBookPracticalGuide": "Acesta este un ghid practic pentru implementarea proiectării bazate pe domeniu (PBD). În timp ce detaliile de implementare se bazeată pe infrastructura ABP, conceptele de bază, principiile şi modelele sunt aplicabile în orice fel de soluţie, chiar dacă nu este o soluţie .NET.",
"TableOfContents": "Cuprins",
"IntroductionToImplementingDDD": "Introducere în implementarea proiectării bazate pe domeniu",
"WhatIsDDD": "Ce este proiectarea bazată pe domeniu?",
"Implementation": "Implementare",
"TheBigPicture": "Imaginea de ansamblu",
"TheBuildingBlock": "The Building Block",
"ExampleUseCase": "Exemplu de utilizare",
"DomainAndApplicationLogic": "Domain Logic & Application Logic",
"Author": "Autor",
"PublishedOn": "Publicat în",
"Page": "Pagina",
"FreeEBook": "E-Book gratuit",
"EBookSignInForDownload": "Pentru a descărca e-book-ul trebuie să vă autentificaţi",
"SignIn": "Autentificare",
"Or": "Sau",
"TellUsAboutYourself": "Spuneţi-ne despre dumneavoastră",
"Surname": "Nume",
"DoYouAgreePrivacyPolicy": "Sunt de acord cu <a href=\"/TermsConditions\">Termenii şi condiţiile<a/> şi <a href=\"/Privacy\">Politica de confidenţialitate</a>.",
"VolosoftMarketingInformationMessage": "Sunt de acord să primesc informaţii, sfaturi şi oferte despre soluţii pentru afaceri şi organizaţii şi alte produse şi servicii Volosoft.",
"VolosoftSharingInformationMessage": "Sunt de acord ca Volosoft să partajeze informaţiile mele cu partenerii selectaţi astfel încât să primesc informaţii relevante despre produsele şi serviciile lor.",
"WeWillSendYouADownloadLink": "Un link pentru descărcarea e-book-ului a fost trimis către {0}.<br/> Verificaţi-vă căsuţele de inbox / junk / spam!",
"InvalidFormInputs": "Vă rugăm să introduceţi informaţia validă specificată în formular.",
"DDDBookEmailBody": "Vă mulţumim. <br /> Pentru a descărca e-book-ul, <a href=\"{0}\">click aici</a>.",
"FreeDDDEBook": "DDD E-Book gratuit"
}
}

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/sk.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "Tmavomodrá téma",
"LightTheme": "Téma Light",
"ProudToWorkWith": "Hrdo spolupracujeme s",
"OurConsumers": "Na ABP Commercial sa spoliehajú stovky podnikov a vývojárov vo viac ako 50 krajinách sveta.",
"OurConsumers": "Na ABP Commercial sa spoliehajú stovky podnikov a vývojárov vo viac ako 70 krajinách sveta.",
"JoinOurConsumers": "Pridajte sa k nim a jednoducho vytvorte úžasné produkty.",
"AdditionalServicesExplanation": "Potrebujete ďalšie alebo vlastné služby? <strong>My a naši partneri vám ich môžeme poskytnúť;</strong>",
"CustomProjectDevelopment": "Vývoj projektu na mieru",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hans.json

@ -106,7 +106,7 @@
"DarkBlueTheme": "深蓝主题",
"LightTheme": "浅色主题",
"ProudToWorkWith": "荣幸与你合作",
"OurConsumers": "全球50多个国家的数百家企业和开发商使用ABP商业版.",
"OurConsumers": "全球70多个国家的数百家企业和开发商使用ABP商业版.",
"JoinOurConsumers": "加它他们并快速构建令人惊叹的产品.",
"AdditionalServicesExplanation": "你是否需要额外或自定义的服务? <strong>我们和我们的合作伙伴可以提供;</strong>",
"CustomProjectDevelopment": "自定义项目开发",

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/zh-Hant.json

@ -104,7 +104,7 @@
"DarkBlueTheme": "深藍主題",
"LightTheme": "淺色主題",
"ProudToWorkWith": "榮幸與你合作",
"OurConsumers": "全球50多個國家的數百家企業和開發商使用ABP商業版.",
"OurConsumers": "全球70多個國家的數百家企業和開發商使用ABP商業版.",
"JoinOurConsumers": "加它他們並快速構建令人驚嘆的產品.",
"AdditionalServicesExplanation": "你是否需要額外或自定義的服務? <strong>我們和我們的合作夥伴可以提供;</strong>",
"CustomProjectDevelopment": "自定義項目開發",

147
abp_io/AbpIoLocalization/AbpIoLocalization/Community/Localization/Resources/ro-RO.json

@ -0,0 +1,147 @@
{
"culture": "ro-RO",
"texts": {
"Permission:CommunityArticle": "Articol comunitar",
"Permission:Edit": "Modifică",
"Waiting": "În aşteptare",
"Approved": "Aprobat",
"Rejected": "Respins",
"Wait": "Pune în aşteptare",
"Approve": "Aprobă",
"Reject": "Respinge",
"ReadArticle": "Citeşte articolul",
"Status": "Starea",
"ContentSource": "Sursa conţinutului",
"Details": "Detalii",
"Url": "Url",
"Title": "Titlu",
"CreationTime": "Data creării",
"Save": "Salvează",
"SameUrlAlreadyExist": "Dacă doriţi să adăugaţi acest articol, ar trebui să schimbaţi adresa Url, întrucât aceeaşi adresa url există deja!",
"UrlIsNotValid": "Url-ul nu este valid.",
"UrlNotFound" : "Url nu a fost găsit.",
"UrlContentNotFound": "Conţinutul url-ului nu a fost găsit.",
"Summary": "Rezumat",
"MostRead": "Cele mai citite",
"Latest": "Recente",
"ContributeAbpCommunity": "Contribuiţi la comunitatea ABP",
"SubmitYourArticle": "Trimiteţi-vă postul",
"ContributionGuide": "Ghid de contribuţie",
"BugReport": "Raportează eroare",
"SeeAllArticles": "Vezi toate postările",
"WelcomeToABPCommunity!": "Bun venit în comunitatea ABP!",
"MyProfile": "Profilul meu",
"MyOrganizations": "Organizaţia mea",
"EmailNotValid": "Vă rugăm să introduceţi o adresa de email validă.",
"FeatureRequest": "Cerere de funcţionalitate",
"CreateArticleTitleInfo": "Titlul postării care va apărea în lista postărilor.",
"CreateArticleSummaryInfo": "Un scurt rezumat al postării care va apărea în lista postărilor.",
"CreateArticleCoverInfo": "Pentru crearea unei postări eficace, adăugaţi o poză de copertă. Încărcaţi imagini cu raport de aspect 16:9 pentru cea mai bună vizualizare. Dimensiunea maximă a fişierului: 1MB.",
"ThisExtensionIsNotAllowed": "Această extensie nu este permisă.",
"TheFileIsTooLarge": "Dimensiunea fişierului este prea mare.",
"GoToTheArticle": "Vezi articolul",
"Contribute": "Contribuie",
"OverallProgress": "Progres total",
"Done": "Gata",
"Open": "Deschide",
"Closed": "Închis",
"LatestQuestionOnThe": "Ultima întrebare de pe",
"Stackoverflow": "Stackoverflow",
"Votes": "voturi",
"Answer": "Răspunde",
"Views": "vizualizări",
"Answered": "Răspunse",
"WaitingForYourAnswer": "În aşteptarea răspunsului dumneavoastră",
"Asked": "întrebate",
"AllQuestions": "Toate întrebările",
"NextVersion": "Următoarea versiune",
"MilestoneErrorMessage": "Nu s-au putut obţine detaliile de referinţă actuale de pe Github.",
"QuestionItemErrorMessage": "Nu s-au putut obţine detaliile de referinţă actuale de pe Stackoverflow.",
"Oops": "Oops!",
"CreateArticleSuccessMessage": "Articolul a fost trimis cu succes. Va fi publicat după ce va fi revizuit de un administrator al site-ului.",
"ChooseCoverImage": "Alegeţi o poză de copertă...",
"CoverImage": "Poză de copertă",
"ShareYourExperiencesWithTheABPFramework": "Împărtăşiţi-vă experienţele cu ABP Framework!",
"Optional": "Opţional",
"UpdateUserWebSiteInfo": "Exemplu: https://johndoe.com",
"UpdateUserTwitterInfo": "Exemplu: johndoe",
"UpdateUserGithubInfo": "Exemplu: johndoe",
"UpdateUserLinkedinInfo": "Exemplu: https://www.linkedin.com/...",
"UpdateUserCompanyInfo": "Exemplu: Volosoft",
"UpdateUserJobTitleInfo": "Exemplu: Software Developer",
"UserName": "Nume de utilizator",
"Company": "Companie",
"PersonalWebsite": "Site web personal",
"RegistrationDate": "Data înregistrării",
"Social": "Social",
"Biography": "Biografie",
"HasNoPublishedArticlesYet": "nu a publicat niciun articol încă",
"Author": "Autor",
"LatestGithubAnnouncements": "Ultimele anunţuri de pe Github",
"SeeAllAnnouncements": "Vezi toate anunţurile",
"LatestBlogPost": "Ultima postare de pe blog",
"Edit": "Modifică",
"ProfileImageChange": "Schimbă poza de profil",
"BlogItemErrorMessage": "Nu s-au putut obţine detaliile ultimei postări de pe from ABP.",
"PlannedReleaseDate": "Data planificată de lansare",
"CommunityArticleRequestErrorMessage": "Nu s-a putut obţine ultima cerere de articol de pe Github.",
"ArticleRequestFromGithubIssue": "Momentan nu există cereri de articole.",
"LatestArticles": "Ultimele postări",
"ArticleRequests": "Cereri de articole",
"AllArticleRequests": "Vedeţi toate cererile de articole",
"SubscribeToTheNewsletter": "Abonaţi-vă la newsletter-ul nostru",
"NewsletterEmailDefinition": "Obţineţi informaţii despre evenimentele din ABP, cum ar fi lansări noi, surse gratuite, articole şi multe altele.",
"NoThanks": "Nu, mulţumesc",
"MaybeLater": "Poate mai târziu",
"JoinOurArticleNewsletter": "Abonaţi-vă la newsletter-ul nostru de articole",
"Community": "Comunitate",
"Marketing": "Marketing",
"CommunityPrivacyPolicyConfirmation": "Sunt de acord cu termenii şi condiţiile şi <a href=\"https://commercial.abp.io/Privacy\">politica de confidenţialitate</a>.",
"ArticleRequestMessageTitle": "<a href=\"https://github.com/abpframework/abp/issues/new\">Deschideţi o problemă pe</a> GitHub pentru a solicita un articol/tutorial pe care doriţi să îl vedeţi pe acest site web.",
"ArticleRequestMessageBody": "Aici, lista articolelor solicitate de către comunitate. Doriţi să scrieţi un articol solicitat? Vă rugăm să daţi click pe cerere şi să vă alăturaţi discuţiei.",
"Language": "Limba",
"CreateArticleLanguageInfo": "Limba pentru conţinutul postării.",
"VideoPost": "Post video",
"Article": "Articol",
"Read": "Citeşte",
"CreateGithubArticleUrlInfo": "Adresa URL originală GitHub a articolului.",
"CreateVideoContentUrlInfo": "Adresa URL originală YouTube a articolului",
"CreateExternalArticleUrlInfo": "Adresa URL originală externă a articolului.",
"VideoContentForm": "Trimite videoclip pe YouTube",
"GithubPostForm": "Trimite articol pe GitHub",
"ExternalPostForm": "Trimite un conţinut extern",
"HowToPost": "Cum postez?",
"Posts": "Postări",
"VideoUrl": "Url Video",
"GithubArticleUrl": "Adresa Url articol Github",
"ExternalArticleUrl": "Adresa Url externă Article",
"CreatePostCoverInfo": "Pentru crearea unei postări eficace, adăugaţi o poză de copertă. Încărcaţi imagini cu raport de aspect 16:9 pentru cea mai bună vizualizare. Dimensiunea maximă a fişierului: 1MB.",
"ThankYouForContribution": "Vă mulţumim pentru că aţi contribuit la comunitatea ABP.",
"GithubArticle": "Articol GitHub",
"GithubArticleSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Scrieţi un articol pe orice repository GitHub folosind formatul Markup. <a target=\"_blank\" href=\"https://github.com/abpframework/abp/blob/dev/docs/en/Community-Articles/2020-12-04-Event-Organizer/Post.md\">exemplu</a>",
"GithubArticleSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Trimiteţi Url-ul articolului folosind formularul.",
"GithubArticleSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Articolul dumneavoastră va fi redat în acest site web.",
"YoutubeVideo": "Videoclip YouTube",
"YoutubeVideoSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Publicaţi-vă videoclipul pe YouTube.",
"YoutubeVideoSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Trimieţi Url-ul videoclipului folosind formularul.",
"YoutubeVideoSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Vizitatorii vor putea să vă vizioneze conţinutul video direct de pe acest site web.",
"ExternalContent": "Conţinut extern",
"ExternalContentSubmitStepOne": "<span class=\"font-weight-bold\">1.</span> Creaţi conţinut pe orice platformă publică (mediu, blogul dumneavoastră sau oriunde doriţi).",
"ExternalContentSubmitStepTwo": "<span class=\"font-weight-bold\">2.</span> Trimiteţi-vă conţinutul URL folosind formularul.",
"ExternalContentSubmitStepThree": "<span class=\"font-weight-bold\">3.</span> Vizitatorii sunt redirecţionaţi către conţinutul de pe site-ul web original.",
"ChooseYourContentType": "Vă rugăm să alegeţi modalitatea pri ncare vreţi să vă adăugaţi conţinutul.",
"PostContentViaGithub": "Vreau să adaug articolul meu de pe <span class=\"font-weight-bold\"><i class=\"fa fa-github\"></i> GitHub</span> conform cu regulile de reducere.",
"PostContentViaYoutube": "Vreau să distribui videoclipurile mele disponibile de pe <span class=\"font-weight-bold\"><i class=\"fa fa-youtube\"></i> YouTube</span> aici.",
"PostContentViaExternalSource": "Vreau să adaug conţinutul pe care l-am publicat pe <span class=\"font-weight-bold\">altă platformă</span> aici.",
"GitHubUserNameValidationMessage": "Numele de utilizator al contului dumneavoastră de GitHub nu poate conţine spaţii goale, vă rugăm să verificaţi că numele de utilizator al contului dumneavoastră de GitHub este corect.",
"PersonalSiteUrlValidationMessage": "Url-ul site-ului dumneavoastră personal nu poate conţine spaţii goale, vă rugăm să verificaţi ca Url-ul site-ului dumneavoastră personal este corect.",
"TwitterUserNameValidationMessage": "Url-ul dumneavoastră de Twitter nu poate conţine spaţii goale, vă rugăm să verificaţi ca Url-ul de Twitter este corect.",
"LinkedinUrlValidationMessage": "Url-ul dumneavoastră de LinkedIn nu poate conţine spaţii goale, vă rugăm să verificaţi ca Url-ul de LinkedIn este corect.",
"NoPostsFound": "Nu s-au găsit postări!",
"SearchInPosts": "Caută în postări...",
"MinimumSearchContent": "Trebuie să introduceţi cel putin 3 caractere!",
"Volo.AbpIo.Domain:060001": "Sursa URL(\"{ArticleUrl}\") nu este URL GitHub",
"Volo.AbpIo.Domain:060002": "Conţinutul articolului nu este disponibil din resursa de pe GitHub(\"{ArticleUrl}\").",
"Volo.AbpIo.Domain:060003": "Nu a fost găsit conţinutul articolului!"
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Docs/Localization/Resources/ro-RO.json

@ -0,0 +1,5 @@
{
"culture": "ro-RO",
"texts": {
}
}

5
abp_io/AbpIoLocalization/AbpIoLocalization/Support/Localization/Resources/ro-RO.json

@ -0,0 +1,5 @@
{
"culture": "ro-RO",
"texts": {
}
}

278
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/ro-RO.json

@ -0,0 +1,278 @@
{
"culture": "ro-RO",
"texts": {
"GetStarted": "Începeţi - Şabloane de pornire",
"Create": "Creează",
"NewProject": "Proiect nou",
"DirectDownload": "Descărcare directă",
"ProjectName": "Nume proiect",
"ProjectType": "Tip proiect",
"DatabaseProvider": "Provider bază de date",
"DatabaseManagementSystem": "Sistem de administrare bază de date",
"NTier": "N-Tier",
"IncludeUserInterface": "Include interfaţa userului",
"CreateNow": "Creează acum",
"TheStartupProject": "Proiectul de pornire",
"Tutorial": "Tutorial",
"UsingCLI": "Folosind CLI",
"SeeDetails": "Vedeţi detalii",
"AbpShortDescription": "ABP Framework este o infrastructură completă pentru crearea aplicaţiilor moderne web prin folosirea celor mai bune practici şi convenţii de dezvoltare software.",
"SourceCodeUpper": "COD SURSĂ",
"LatestReleaseLogs": "Cele mai recente jurnale de lansare",
"Infrastructure": "Infrastructura",
"Architecture": "Arhitectura",
"Modular": "Modular",
"DontRepeatYourself": "Nu vă repetaţi",
"DeveloperFocused": "Axat pe dezvoltator",
"FullStackApplicationInfrastructure": "Infrastructură de aplicaţii full stack.",
"DomainDrivenDesign": "Domain Driven Design",
"DomainDrivenDesignExplanation": "Proiectat şi dezvoltat pe baza modelelor şi principiilor DDD. Oferă un model stratificat pentru aplicaţia dumneavoastră.",
"Authorization": "Autorizare",
"AuthorizationExplanation": "Autorizare avansată pe bază de utilizator, rol şi sistem de permisiuni. Construit pe biblioteca Microsoft Identity.",
"MultiTenancy": "Multi-Tenancz",
"MultiTenancyExplanationShort": "Aplicaţii SaaS simplificate! Multi-Tenancy integrată de la baza de date până la UI.",
"CrossCuttingConcerns": "Cross Cutting Concerns",
"CrossCuttingConcernsExplanationShort": "Infrastructură completă pentru autorizare, validare, gestionarea excepţiilor, stocarea în cache, înregistrarea auditului, gestionarea tranzacţiilor şi multe altele.",
"BuiltInBundlingMinification": "Grupare şi minificare incorporate",
"BuiltInBundlingMinificationExplanation": "Nu este nevoie să utilizaţi instrumente externe pentru grupare şi minificare. ABP oferă un mod mai simplu, dinamic, puternic, modular şi incorporat!",
"VirtualFileSystem": "Sistem de fişiere virtuale",
"VirtualFileSystemExplanation": "Încorporaţi view-uri, scripturi, stiluri, imagini... in pachete/librării şi refolosiţi-le în diferite aplicaţii.",
"Theming": "Tematică",
"ThemingExplanationShort": "Utilizaţi şi personalizaţi tema UI standard, bazată pe UI, sau creaţi-o pe a dumneavoastră.",
"BootstrapTagHelpersDynamicForms": "Bootstrap Tag Helpers & Dynamic Forms",
"BootstrapTagHelpersDynamicFormsExplanation": "În loc să scrieţi manual detaliile repetate ale componentelor bootstrap, utilizaţi tag helperele ABP pentru a simplifica şi profita de inteligenţă. Construiţi rapid formulare de interfaţă bazate pe un model C# utilizând ajutorul pentru formulare dinamice.",
"HTTPAPIsDynamicProxies": "HTTP APIs & Dynamic Proxies",
"HTTPAPIsDynamicProxiesExplanation": "Expuneţi automat serviciile aplicaţiilor sub formă de API-uri HTTP şi folosiţi-le cu JavaScript dinamic si proxy C#.",
"CompleteArchitectureInfo": "Arhitectură modernă pentru a crea soluţii software care pot fi întreţinute.",
"DomainDrivenDesignBasedLayeringModelExplanation": "Vă ajută să implementaţi o arhitectură stratificată DDD şi să construiţi o bază de cod uşor de întreţinut.",
"DomainDrivenDesignBasedLayeringModelExplanationCont": "Oferă şabloane de pornire, abstractizări, clase de bază, servicii, documentaţie şi ghiduri pentru a vă ajuta să vă dezvoltaţi aplicaţia bazându-vă pe principiile şi tiparele DDD.",
"MicroserviceCompatibleModelExplanation": "Framework-ul de bază şi modulele pre-construite sunt proiectate având în vedere arhitectura microservice.",
"MicroserviceCompatibleModelExplanationCont": "Oferă infrastructură, integrări, exemple şi documentaţie pentru a implementa mai uşor soluţiile de microservicii, în timp ce nu aduce complexitate suplimentară dacă doriţi o aplicaţie monolitică.",
"ModularInfo": "ABP oferă un sistem de module care vă permite să dezvoltaţi module de aplicaţie reutilizabile, să vă conectaţi la evenimentele din ciclul de viaţă ale aplicaţiei şi să exprimaţi dependenţe între părţile centrale ale sistemului dumneavoastră.",
"PreBuiltModulesThemes": "Module şi teme pro-construite.",
"PreBuiltModulesThemesExplanation": "Modulele şi temele open source sunt gata de utilizare în aplicaţia dumneavoastră.",
"NuGetNPMPackages": "Pachete NuGet & NPM",
"NuGetNPMPackagesExplanation": "Distribuite sub formă de pachete NuGet & NPM. Uşor de instalat şi actualizat.",
"ExtensibleReplaceable": "Extensibil/Înlocuibil",
"ExtensibleReplaceableExplanation": "Toate serviciile şi modulele sunt dezvoltate pentru extensibilitate. Puteţi înlocui servicii, pagini, stiluri şi componente.",
"CrossCuttingConcernsExplanation2": "Menţineţi baza codului redusă, astfel încât să vă puteţi concentra asupra codului care e specific afacerii dumneavoastră.",
"CrossCuttingConcernsExplanation3": "Nu pierdeţi timp implementând cerinţe comune de aplicaţie pentru mai multe proiecte.",
"AuthenticationAuthorization": "Autentificare & Autorizare",
"ExceptionHandling": "Tratarea excepţiilor",
"Validation": "Validare",
"DatabaseConnection": "Conectare la baza de date",
"TransactionManagement": "Administrarea tranzacţiilor",
"AuditLogging": "Audit Logging",
"Caching": "Caching",
"Multitenancy": "Multitenancy",
"DataFiltering": "Filtrarea datelor",
"ConventionOverConfiguration": "Convention Over Configuration",
"ConventionOverConfigurationExplanation": "ABP implementează convenţii de aplicaţii comune în mod implicit, cu o configuraţie minimă sau zero.",
"ConventionOverConfigurationExplanationList1": "Auto înregistrează serviciile cunoscute pentru injectarea dependinţei..",
"ConventionOverConfigurationExplanationList2": "Expune serviciile aplicaţiei ca API-uri HTTP prin convenţii de denumire.",
"ConventionOverConfigurationExplanationList3": "Creează proxy-uri dinamice HTTP client pentru C# şi JavaScript.",
"ConventionOverConfigurationExplanationList4": "Oferă repository-uri implicite pentru entităţile dumneavoastră.",
"ConventionOverConfigurationExplanationList5": "Gestionează unitatea de lucru pe request web sau metodă de serviciu a aplicaţiei.",
"ConventionOverConfigurationExplanationList6": "Publică crearea, actualizarea şi ştergerea evenimentelor pentru entităţile dumneavoastră.",
"BaseClasses": "Clase de bază",
"BaseClassesExplanation": "Clase de bază pre-construite pentru tipare comune de aplicaţie.",
"DeveloperFocusedExplanation": "ABP este pentru dezvoltatori.",
"DeveloperFocusedExplanationCont": "Aceasta îşi propune să vă simplifice dezvoltarea zilnică de software, fără a vă restricţiona să scrieţi cod de nivel scăzut.",
"SeeAllFeatures": "Vedeţi toate funcţionalităţile",
"CLI_CommandLineInterface": "CLI (Command Line Interface)",
"CLI_CommandLineInterfaceExplanation": "Include un CLI pentru a vă ajuta să automatizaţi crearea de noi proiecte şi adăugarea de noi module.",
"StartupTemplates": "Proiecte de lansare",
"StartupTemplatesExplanation": "Diverse proiecte de lansare furnizează o soluţie complet configurată pentru a vă începe dezvoltarea.",
"BasedOnFamiliarTools": "Bazat pe instrumente familiare",
"BasedOnFamiliarToolsExplanation": "Construit şi integrat cu instrumente populare pe care le ştiţi deja. Curbă de învăţare joasă, adaptare uşoară, dezvoltare confortabilă.",
"ORMIndependent": "ORM Independent",
"ORMIndependentExplanation": "Framework-ul de bază este independent de ORM/bază de date şi poate funcţiona cu orice sursă de date. Furnizorii Entity Framework Core şi MongoDB sunt deja disponibili.",
"Features": "Exploraţi caracteristicile framework-ului ABP Framework",
"ABPCLI": "ABP CLI",
"Modularity": "Modularitate",
"BootstrapTagHelpers": "Bootstrap Tag Helpers",
"DynamicForms": "Formulare dinamice",
"BundlingMinification": "Grupare & Minificare",
"BackgroundJobs": "Background Jobs",
"BackgroundJobsExplanation": "Definiţi clase simple pentru a executa task-uri în fundal, aşezate în coadă. Folosiţi managerul de taskuri încorporat sau integraţi-l pe al dumneavoastră. Integrările <a href=\"{0}\">Hangfire</a> & <a href=\"{1}\">RabbitMQ</a> sunt deja disponibile.",
"DDDInfrastructure": "Infrastructură DDD",
"DomainDrivenDesignInfrastructure": "Infrastructură Domain Driven Design",
"AutoRESTAPIs": "Auto REST APIs",
"DynamicClientProxies": "Dynamic Client Proxies",
"DistributedEventBus": "Distributed Event Bus",
"DistributedEventBusWithRabbitMQIntegration": "Distributed Event Bus with RabbitMQ Integration",
"TestInfrastructure": "Infrastructură de test",
"AuditLoggingEntityHistories": "Jurnalul de audit şi istoricul entităţilor",
"ObjectToObjectMapping": "Mapare obiect la obiect",
"ObjectToObjectMappingExplanation": "Abstractizarea <a href=\"{0}\">mapării obiect la obiect</a> cu integrare AutoMapper.",
"EmailSMSAbstractions": "Abstractizări Email & SMS",
"EmailSMSAbstractionsWithTemplatingSupport": "Abstractizări de Email & SMS cu asistenţă pentru modelare",
"Localization": "Localizare",
"SettingManagement": "Administrarea setărilor",
"ExtensionMethods": "Metode de extindere",
"ExtensionMethodsHelpers": "Metode de extindere & Ajutoare",
"AspectOrientedProgramming": "Programare orientată spre aspect",
"DependencyInjection": "Injectarea de dependinţe",
"DependencyInjectionByConventions": "Injectarea dependinţei prin convenţii",
"ABPCLIExplanation": "ABP CLI (Command Line Interface) este un instrument de linie de comandă pentru efectuarea câtorva operaţii comune pentru soluţiile bazate pe ABP.",
"ModularityExplanation": "ABP asigură o infrastructură completă pentru construirea modulelor aplicaţiei dumneavoastră, care pot avea entităţi, servicii, integrări cu baze de date, API-uri, componente UI şi aşa mai departe..",
"MultiTenancyExplanation": "ABP nu numai că acceptă dezvoltarea de aplicaţii multi-tenant, dar, de asemenea, face ca şi codul dumneavoastră să nu fie în mare parte conştient de multi-tenancy.",
"MultiTenancyExplanation2": "Poate detecta automat tenantul curent, izola datele unor tenanţi diferiţi unul de celălalt.",
"MultiTenancyExplanation3": "Acceptă o singură bază de date, bază de date per tenant şi abordări hibride.",
"MultiTenancyExplanation4": "Vă focusaţi pe codul dumneavoastră şi lăsaţi framework-ul să se ocupe de multi-tenancy pentru dumneavoastră.",
"BootstrapTagHelpersExplanation": "În loc să scrieţi manual detaliile repetate ale componentelor bootstrap, folosiţi tag helperele ABP pentru a simplifica şi profita de inteligenţă. Puteţi folosi cu siguranţă Bootstrap ori de câte ori aveţi nevoie de el.",
"DynamicFormsExplanation": "Formulare dinamice & tag helpere de intrare pot crea formularul complet dintr-o clasă C# ca model.",
"AuthenticationAuthorizationExplanation": "Opţiuni variate de autentificare şi autorizare integrate cu ASP.NET Core Identity & IdentityServer4. Furnizează un sistem de permisiuni extensibil şi detaliat.",
"CrossCuttingConcernsExplanation": "Nu vă repetaţi pentru a implementa din nou şi din nou toate aceste lucruri obişniuite. Concentraţi-vă pe codul dumneavoastră de business şi lăsaţi ABP să le automatizeze prin convenţii.",
"DatabaseConnectionTransactionManagement": "Conectare la baza de date & Gestionarea tranzacţiilor",
"CorrelationIdTracking": "Correlation-Id Tracking",
"BundlingMinificationExplanation": "ABP oferă un sistem simplu, dinamic, puternic, modular şi încorporat de grupare şi minimizare.",
"VirtualFileSystemnExplanation": "Sistemul fişierelor virtuale face posibilă administrare fişierelor care nu există fizic pe sistemul de fişiere (disk). Este folosit în principal pentru a încorpora fişiere (js, css, images, cshtml...) în ansambluri şi să le folosească sub formă de fişiere fizice în timpul rulării.",
"ThemingExplanation": "Sistemul de teme permite dezvoltarea aplicaţiei & modulelor independente de tema prin definirea unui set comun de librării şi aspecte de bază, bazate pe ultimul framework Bootstrap.",
"DomainDrivenDesignInfrastructureExplanation": "O infrastructură completă pentru construirea aplicaţiilor stratificate, bazată pe tipare & principii Domain Driven Design;",
"Specification": "Specificaţie",
"Repository": "Repository",
"DomainService": "Domain Service",
"ValueObject": "Value Object",
"ApplicationService": "Application Service",
"DataTransferObject": "Obiect de transfer de date",
"AggregateRootEntity": "Aggregate Root, Entity",
"AutoRESTAPIsExplanation": "ABP poate configura automat serviciile aplicaţiei sub formă de controllere API prin convenţie.",
"DynamicClientProxiesExplanation": "Folosiţi-vă cu uşurinţă API-urile din JavaScript şi clienţi C#.",
"DistributedEventBusWithRabbitMQIntegrationExplanation": "Publicaţi şi utilizaţi cu uşurinţă evenimentele distribuite utilizând Distributed Event Bus încorporat cu integrarea RabbitMQ disponibilă.",
"TestInfrastructureExplanation": "Framework-ul a fost dezvoltat cu testarea unităţii şi integrării în minte. Vă oferă clase de bază pentru a o uşura. Şabloanele de pornire sunt pre-configurate pentru testare.",
"AuditLoggingEntityHistoriesExplanation": "Jurnal de audit încorporat pentru aplicaţii critice pentru afaceri. Solicitare, serviciu, jurnal de audit la nivel de metodă şi istoric de entităţi cu detalii la nivel de proprietate.",
"EmailSMSAbstractionsWithTemplatingSupportExplanation": "Abstractizările IEmailSender şi ISmsSender decuplează logica aplicaţiei de infrastructură. Sistemul avansat de şabloane de email permite crearea şi localizarea şabloanelor de email şi utilizarea lor cu uşurinţă ori de câte ori este necesar.",
"LocalizationExplanation": "Sistemul de localizare vă permite să creaţi resurse în JSON simplu şi să le folosiţi pentru a vă localiza UI-ul dumneavoastră. Suportă sisteme avansate precum moştenirea, extinderea, şi integrarea cu JavaScript în timp ce e pe deplin compatibilă cu sistemul de localizare al AspNet Core.",
"SettingManagementExplanation": "Definiţi setări pentru aplicaţia dumneavoastră şi Define settings for your application and get values on runtime based on the current configuration, tenant and user.",
"ExtensionMethodsHelpersExplanation": "Don't repeat yourself even for trivial code parts. Extensions & helpers for standard types makes your code much cleaner and easy to write.",
"AspectOrientedProgrammingExplanation": "Furnizează o infrastructură confortabilă pentru crearea proxy-urilor dinamice şi implementarea programării orientată aspect. Interceptează orice clasă şi execută codul dumneavoastră înainte & după orice executare de metodă.",
"DependencyInjectionByConventionsExplanation": "Nu este nevoie să vă înregistraţi clasele pentru injectarea manuală a dependinţelor. Înregistrează în mod automat tipurile de servicii comune prin convenţie. Pentru alte tipuri de servicii, puteţi folosi interfeţe şi atribute pentru a o face mai uşor si pe loc.",
"DataFilteringExplanation": "Definiţi şi utilizaţi filtre de date care sunt aplicate automat atunci când interogaţi entităţi din baza de date. Filtre Soft Delete & MultiTenant sunt prevăzute în mod implicit atunci când implementaţi interfeţe simple.",
"PublishEvents": "Publicaţi evenimente",
"HandleEvents": "Gestionaţi evenimente",
"AndMore": "şi multe altele...",
"Code": "Cod",
"Result": "Rezultat",
"SeeTheDocumentForMoreInformation": "Consultaţi <a href=\"{1}\">{0} documentul</a> pentru mai multe informaţii",
"IndexPageHeroSection": "<span class=\"first-line shine\"><strong>open source</strong></span><span class=\"second-line text-uppercase\">Web Application<br />Framework </span><span class=\"third-line shine2\"><strong>pentru asp.net core</strong></span>",
"UiFramework": "Framework UI",
"EmailAddress": "Adresă de email",
"Mobile": "Mobil",
"ReactNative": "React nativ",
"Strong": "Puternic",
"Complete": "Complet",
"BasedLayeringModel": "Based Layering Model",
"Microservice": "Microserviciu",
"Compatible": "Compatibil",
"MeeTTheABPCommunityInfo": "Misiunea noastră este de a crea un mediu în care dezvoltatorii să se ajute reciproc cu articole, tutoriale, studii de caz etc. şi să cunoască oameni cu aceleaşi idei.",
"JoinTheABPCommunityInfo": "Implicaţi-vă într-o comunitate vibrantă şi deveniţi un contribuitor la ABP Framework!",
"AllArticles": "Toate articolele",
"SubmitYourArticle": "Trimiteţi-vă articolul",
"DynamicClientProxyDocument": "Consultaţi documentaţia pentru client proxy dinamic pentru <a href=\"{0}\">JavaScript</a> & <a href=\"{1}\">C#</a>.",
"EmailSMSAbstractionsDocument": "Consultaţi documentele de <a href=\"{0}\">emailing</a> and <a href=\"{1}\">trimiterea de SMS</a> pentru mai multe informaţii.",
"CreateProjectWizard": "Acest formular crează un proiect nou începând cu şablonul de pornire, care este configurat corespunzător pentru a începe direct cu proiectul.",
"TieredOption": "Crează o soluţie pe mai multe niveluri în care straturile Web API şi HTTP sunt separate fizic. Dacă nu este bifată, creează o soluţie stratificată mai puţin complexă şi potrivită pentru majoritatea scenariilor.",
"SeparateIdentityServerOption": "Separă partea serverului în două aplicaţii: prima este pentru serverul de identitate, iar a doua pentru serverul dumneavoastră de HTTP API.",
"UseslatestPreVersion": "Foloseşte ultima versiune pre-lansare",
"ReadTheDocumentation": "<span class=\"text-primary\">Citiţi</span><span class=\"text-success\"> Documentaţia</span>",
"Documentation": "Documentaţie",
"GettingStartedTutorial": "Tutorial de pornire",
"ApplicationDevelopmentTutorial": "Tutorial de dezvoltare a aplicaţiei",
"TheStartupTemplate": "Şablonul de pornire",
"InstallABPCLIInfo": "ABP CLI este cea mai rapidă metodă de a porni o soluţie nouă cu framework-ul ABP. Instalaţi ABP CLI folosind o fereastră de linii de comandă:",
"DifferentLevelOfNamespaces": "Puteţi folosi nivele diferite de spaţii de nume; e.g. BookStore, Acme.BookStore or Acme.Retail.BookStore.",
"ABPCLIExamplesInfo": "comanda <strong>new</strong> creează o <strong>aplicaţie stratificată MVC</strong> cu <strong>Entity Framework Core</strong> ca şi furnizor de baze de date. Totuşi, are şi alte opţiuni. Exemple:",
"SeeCliDocumentForMoreInformation": "Consultaţi <a href=\"{0}\">documentul ABP CLI</a> pentru mai multe opţiuni sau selectaţi tab-ul de \"Descărcare directă\" de deasupra.",
"Optional": "Opţional",
"LocalFrameworkRef": "Pastraţi referinţa proiectului local pentru pachetele framework-ului.",
"BlobStoring": "Depozitare BLOB",
"BlobStoringExplanation": "Sistemul de depozitare BLOB oferă o abstractizare pentru lucrul cu BLOB-uri. ABP oferă câteva integrări prestabilite pentru furnizorii de stocare (Azure, AWS, File System, Database, etc.) pe care le puteţi folosi cu uşurinţă în aplicaţiile dumneavoastră.",
"TextTemplating": "Modelare text",
"TextTemplatingExplanation": "Modelarea textului este folosită pentru a reda dinamic conţinuturile bazate pe un şablon şi un model (un obiect de date). De exemplu, o puteţi folosi pentru a crea conţinuturi dinamice de email cu un şablon predefinit.",
"MultipleUIOptions": "Opţiuni UI multiple",
"MultipleDBOptions": "Furnizori de baze de date multipli",
"MultipleUIOptionsExplanation": "Framework-ul de bază este conceput ca independent de UI şi poate funcţiona cu orice tip de sistem UI, în timp ce mai multe opţiuni pre-construite şi integrate sunt oferite din start.",
"MultipleDBOptionsExplanation": "Framework-ul poate lucra cu orice sursă de date, în timp ce furnizorii următori sunt dezvoltaţi şi acceptaţi oficial;",
"SelectLanguage": "Selectaţi limba",
"LatestArticleOnCommunity": "Ultimul articol de pe comunitatea ABP",
"Register": "Întregistrare",
"IsDownloadable": "Poate fi descărcat",
"DatabaseOptions": "Opţiunile bazei de date",
"BackToPackagesPage": "Înapoi la pagina pachetelor",
"HowToInstall": "Cum instalez",
"SeeOnNpm": "Vedeţi pe NPM",
"SeeOnNuget": "Vedeţi pe Nuget",
"MVCGulpCommandExplanation": "Dacă folosiţi MVC (Razor Pages) UI, atunci rulaţi comanda the \"gulp\" după instalarea pachetelor.",
"UsingABPCLI": "Folosind <a href=\"https://docs.abp.io/en/abp/latest/CLI\">Abp CLI</a>",
"WithoutABPCLI": "Fară ABP CLI",
"ABPCLIModuleDependency": "Abp Cli adaugă automat dependenţa modulelor.",
"AddModuleDependency": "Apoi adăugaţi dependenţa modulului",
"Packages": "Pachete",
"NugetPackages": "Pachete Nuget",
"NPMPackages": "Pachete NPM",
"SeeDocs": "Consultaţi documentele",
"None": "Niciuna",
"Application": "Aplicaţie",
"Module": "Module",
"PackageName": "Nume pachet",
"LicenseURL": "URL licenţă",
"License": "Licenţă",
"ProjectCreationSuccessMessage": "Proiectul dumneavoastră a fost creat cu succes",
"HowToRunSolution": "Cum vă rulaţi soluţia?",
"GettingStartedMessage": "Consultaţi documentul de pornire pentru a învăţa cum să vă configuraţi şi să rulaţi soluţia dumneavoastră.",
"WebAppDevTutorial": "Tutorial Web App Dev",
"WebAppDevTutorialMessage": "Consultaţi documentul de dezvoltare a aplicaţiilor web pentru un exemplu de dezvoltare pas cu pas.",
"CommunityArticles": "Articolele comunităţii",
"CommunityArticleMessage": "Verificaţi platforma comunităţii ABP pentru a citi articole utile pentru framework-ul ABP.",
"InvestigateSolutionDetails": "Investigaţi detaliile soluţiei",
"StartupTemplateDocumentationMessage": "Consultaţi documentul şablonului de pornire a aplicaţiei pentru a învăţa arhitectura şi strucutra soluţiei dumneavoastră.",
"ClientSideDevelopment": "Dezvoltarea clientului",
"ClientSideDevelopmentDocumentationMessage": "Consultaţi documentul {0} pentru a învăţa punctele cheie pentru dezvoltarea interfeţei de utilizator.",
"DatabaseProviderDocumentationMessage": "Consultaţi documentul {0} pentru a învăţa punctele cheie pentru dezvoltarea straturilor bazei de date.",
"ABPCommercialExplanationMessage": "ABP Commercial oferă module premium, teme, isntrumente şi asistenţă pentru framework-ul ABP.",
"ImplementingDDD": "Implementarea Domain Driven Design",
"DDDBookExplanation": "Un ghid practic pentru implementarea Domain Driven Design în framework-ul ABP.",
"Overview": "Prezentare generală",
"DDDBookPracticalGuide": "Acesta este un ghid practic pentru implementarea Domain Driven Design (DDD). În timp ce detaliile implementării se bazează pe infrastructura framework-ului ABP, conceptele de bază, principiile şi modelele pot fi aplicate oricărei soluţii, chiar dacă nu este una .NET.",
"TableOfContents": "Cuprins",
"IntroductionToImplementingDDD": "Introducere în Implementarea Domain Driven Design",
"WhatIsDDD": "Ce este Domain Driven Design?",
"Implementation": "Implementare",
"TheBigPicture": "Privire de ansamblu",
"TheBuildingBlock": "The Building Block",
"ExampleUseCase": "Exemplu de Use Case",
"DomainAndApplicationLogic": "Domain Logic & Application Logic",
"Author": "Autor",
"Pages": "Pagini",
"PublishedOn": "Publicat pe",
"FreeEBook": "E-Book gratuit",
"Download": "Descărcaţi",
"EBookSignInForDownload": "Pentru a descărca e-book-ul trebuie să vă autentificaţi",
"SignIn": "Autentificaţi-vă",
"Or": "Sau",
"TellUsAboutYourself": "Spuneţi-ne un pic despre dumneavoastră",
"Name": "Nume",
"Surname": "Nume",
"CompanyName": "Nume companie",
"DoYouAgreePrivacyPolicy": "Sunt de acord cu <a href=\"https://account.abp.io/Account/TermsConditions\">Termenii & condiţiile</a> şi <a href=\"https://account.abp.io/Account/Privacy\">Politica de confidenţialitate</a>.",
"Free": "Gratuit",
"DDDEBook": "E-book DDD",
"PracticalGuideForImplementingDDD": "Această carte este un ghid practic pentru implementarea Domain Driven Design în framework-ul ABP.",
"IntroducingDDD": "Introducere în Domain Driven Design",
"DDDLayersAndCleanArchitecture": "Straturile DDD & Arhitectură curată",
"LayeringOfADotnetSolution": "Stratificarea unei soluţii .NET",
"ImplementingDDDBuildingBlocks": "Implementând DDD Building Blocks",
"DomainVsApplicationLogic": "Domain Logic vs Application Logic",
"SamplesAndDiscussions": "Exemple & Discuţii",
"EmailNotValid": "Vă rugăm să introduceţi o adresa de email validă.",
"WeWillSendYouADownloadLink": "Un link care conţine e-book-ul a fost trimis către {0}. Verificaţi-vă folderele de inbox, junk sau spam!",
"GoHome": "Pagina principală",
"InvalidFormInputs": "Vă rugăm, introduceţi informaţia validă specificată în formular.",
"DDDBookEmailBody": "Vă mulţumim. <br /> Pentru a descărca cartea, <a href=\"{0}\">click aici</a>.",
"SubscribeToNewsletter": "Abonaţi-vă la newsletter pentru a primi informaţii despre evnimentele din platforma ABP.IO, precum noi lansări, articole, oferte şi multe altele.",
"FirstEdition": "Prima ediţie",
"ThankYou": "Vă mulţumim!",
"CheckboxMandatory": "Trebuie să bifaţi asta pentru a continua!"
}
}

4
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/zh-Hans.json

@ -218,7 +218,7 @@
"LicenseURL": "许可URL",
"License": "许可",
"ProjectCreationSuccessMessage": "你的项目创建成功",
"HowToRunSolution": "如何运行你的解决方案n?",
"HowToRunSolution": "如何运行你的解决方案?",
"GettingStartedMessage": "查看入门文档了解如何配置和运行你的解决方案.",
"WebAppDevTutorial": "Web App 开发教程",
"WebAppDevTutorialMessage": "查看web应用程序开发教程文档,一步一步的开发示例.",
@ -231,4 +231,4 @@
"DatabaseProviderDocumentationMessage": "查看{0}文档来学习用数据库层开发.",
"ABPCommercialExplanationMessage": "ABP商业版为ABP框架提供了高级模块,主题,工具和支持."
}
}
}

14
common.props

@ -19,4 +19,18 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Remove="*.abppkg.json"/>
<None Include="*.abppkg.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
<ItemGroup Condition="$(AssemblyName.EndsWith('HttpApi.Client'))">
<EmbeddedResource Include="**\*generate-proxy.json" />
<Content Remove="**\*generate-proxy.json" />
</ItemGroup>
</Project>

140
docs/en/API/Swagger-Integration.md

@ -0,0 +1,140 @@
# Swagger Integration
[Swagger (OpenAPI)](https://swagger.io/) is a language-agnostic specification for describing REST APIs. It allows both computers and humans to understand the capabilities of a REST API without direct access to the source code. Its main goals are to:
- Minimize the amount of work needed to connect decoupled services.
- Reduce the amount of time needed to accurately document a service.
ABP Framework offers a prebuilt module for full Swagger integration with small configurations.
## Installation
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
If installation is needed, it is suggested to use the [ABP CLI](CLI.md) to install this package.
### Using the ABP CLI
Open a command line window in the folder of the `Web` or `HttpApi.Host` project (.csproj file) and type the following command:
```bash
abp add-package Volo.Abp.Swashbuckle
```
### Manual Installation
If you want to manually install;
1. Add the [Volo.Abp.Swashbuckle](https://www.nuget.org/packages/Volo.Abp.Swashbuckle) NuGet package to your `Web` or `HttpApi.Host` project:
`Install-Package Volo.Abp.Swashbuckle`
2. Add the `AbpSwashbuckleModule` to the dependency list of your module:
```csharp
[DependsOn(
//...other dependencies
typeof(AbpSwashbuckleModule) // <-- Add module dependency like that
)]
public class YourModule : AbpModule
{
}
```
## Configuration
First, we need to use `AddAbpSwaggerGen` extension to configure Swagger in `ConfigureServices` method of our module.
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = contex.Services;
//... other configarations.
services.AddAbpSwaggerGen(
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
}
);
}
```
Then we can use Swagger UI by calling `UseAbpSwaggerUI` method in the `OnApplicationInitialization` method of our module.
```csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
//... other configarations.
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Test API");
});
//... other configarations.
}
```
## Using Swagger with OAUTH
For non MVC/Tiered applications, we need to configure Swagger with OAUTH to handle authorization.
> ABP Framework uses IdentityServer by default. To get more information about IDS, check this [documentation](Modules/IdentityServer.md).
To do that, we need to use `AddAbpSwaggerGenWithOAuth` extension to configure Swagger with OAuth issuer and scopes in `ConfigureServices` method of our module.
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = contex.Services;
//... other configarations.
services.AddAbpSwaggerGenWithOAuth(
"https://localhost:44341", // authority issuer
new Dictionary<string, string> //
{ // scopes
{"Test", "Test API"} //
}, //
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
}
);
}
```
Then we can use Swagger UI by calling `UseAbpSwaggerUI` method in the `OnApplicationInitialization` method of our module.
> Do not forget to set `OAuthClientId` and `OAuthClientSecret`.
```csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
//... other configarations.
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Test API");
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
options.OAuthClientId("Test_Swagger"); // clientId
options.OAuthClientSecret("1q2w3e*"); // clientSecret
});
//... other configarations.
}
```

2
docs/en/Authorization.md

@ -256,7 +256,7 @@ myGroup.AddPermission("Book_Creation")
#### Depending on a Global Feature
Use the `RequireFeatures` extension method on your permission definition to make the permission available only if a given feature is enabled:
Use the `RequireGlobalFeatures` extension method on your permission definition to make the permission available only if a given feature is enabled:
````csharp
myGroup.AddPermission("Book_Creation")

23
docs/en/Background-Jobs-Hangfire.md

@ -79,3 +79,26 @@ After you have installed these NuGet packages, you need to configure your projec
}
````
### Dashboard Authorization
Hangfire Dashboard provides information about your background jobs, including method names and serialized arguments as well as gives you an opportunity to manage them by performing different actions – retry, delete, trigger, etc. So it is important to restrict access to the Dashboard.
To make it secure by default, only local requests are allowed, however you can change this by following the [official documentation](http://docs.hangfire.io/en/latest/configuration/using-dashboard.html) of Hangfire.
You can integrate the Hangfire dashboard to [ABP authorization system](Authorization.md) using the **AbpHangfireAuthorizationFilter**
class. This class is defined in the `Volo.Abp.Hangfire` package. The following example, checks if the current user is logged in to the application:
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() }
});
If you want to require an additional permission, you can pass it into the constructor as below:
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter("MyHangFireDashboardPermissionName") }
});
**Important**: `UseHangfireDashboard` should be called after the authentication middleware in your `Startup` class (probably at the last line). Otherwise,
authorization will always fail!

29
docs/en/Best-Practices/Entity-Framework-Core-Integration.md

@ -66,12 +66,7 @@ public static string Schema { get; set; } = AbpIdentityConsts.DefaultDbSchema;
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ConfigureIdentity(options =>
{
options.TablePrefix = TablePrefix;
options.Schema = Schema;
});
builder.ConfigureIdentity();
}
````
@ -80,25 +75,20 @@ protected override void OnModelCreating(ModelBuilder builder)
````C#
public static class IdentityDbContextModelBuilderExtensions
{
public static void ConfigureIdentity(
[NotNull] this ModelBuilder builder,
Action<IdentityModelBuilderConfigurationOptions> optionsAction = null)
public static void ConfigureIdentity([NotNull] this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
var options = new IdentityModelBuilderConfigurationOptions();
optionsAction?.Invoke(options);
builder.Entity<IdentityUser>(b =>
{
b.ToTable(options.TablePrefix + "Users", options.Schema);
b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users", AbpIdentityDbProperties.DbSchema);
b.ConfigureByConvention();
//code omitted for brevity
});
builder.Entity<IdentityUserClaim>(b =>
{
b.ToTable(options.TablePrefix + "UserClaims", options.Schema);
b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "UserClaims", AbpIdentityDbProperties.DbSchema);
b.ConfigureByConvention();
//code omitted for brevity
});
@ -109,17 +99,6 @@ public static class IdentityDbContextModelBuilderExtensions
````
* **Do** call `b.ConfigureByConvention();` for each entity mapping (as shown above).
* **Do** create a **configuration options** class by inheriting from the `AbpModelBuilderConfigurationOptions`. Example:
````C#
public class IdentityModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions
{
public IdentityModelBuilderConfigurationOptions()
: base(AbpIdentityConsts.DefaultDbTablePrefix, AbpIdentityConsts.DefaultDbSchema)
{
}
}
````
### Repository Implementation

26
docs/en/Best-Practices/MongoDB-Integration.md

@ -55,10 +55,7 @@ protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
modelBuilder.ConfigureIdentity(options =>
{
options.CollectionPrefix = CollectionPrefix;
});
modelBuilder.ConfigureIdentity();
}
```
@ -73,36 +70,19 @@ public static class AbpIdentityMongoDbContextExtensions
{
Check.NotNull(builder, nameof(builder));
var options = new IdentityMongoModelBuilderConfigurationOptions();
optionsAction?.Invoke(options);
builder.Entity<IdentityUser>(b =>
{
b.CollectionName = options.CollectionPrefix + "Users";
b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "Users";
});
builder.Entity<IdentityRole>(b =>
{
b.CollectionName = options.CollectionPrefix + "Roles";
b.CollectionName = AbpIdentityDbProperties.DbTablePrefix + "Roles";
});
}
}
```
- **Do** create a **configuration options** class by inheriting from the `AbpMongoModelBuilderConfigurationOptions`. Example:
```c#
public class IdentityMongoModelBuilderConfigurationOptions
: AbpMongoModelBuilderConfigurationOptions
{
public IdentityMongoModelBuilderConfigurationOptions()
: base(AbpIdentityConsts.DefaultDbTablePrefix)
{
}
}
```
### Repository Implementation
- **Do** **inherit** the repository from the `MongoDbRepository<TMongoDbContext, TEntity, TKey>` class and implement the corresponding repository interface. Example:

2
docs/en/Blog-Posts/2020-10-15 v3_3_Preview/POST.md

@ -213,7 +213,7 @@ There are some breaking changes with the Blazor UI. If you've built an applicati
When you create a new project, profile management doesn't work, you get an exception because it can't find the `/libs/cropperjs/css/cropper.min.css` file. To fix the issue;
* Add `"@volo/account": "^3.3.0-rc.1"` to the `package.json` in the `.Host` project.
* Run `yarn` (or `npm install`), then `gulp` on a command line terminal in the root folder of the `.Host` project.
* Run `yarn` (or `npm install`), then `abp install-libs` on a command line terminal in the root folder of the `.Host` project.
### Multi-Tenant Social Logins

216
docs/en/Blog-Posts/2021-07-28-lepton-x-release/POST.md

@ -0,0 +1,216 @@
# LeptonX Alpha Release
We are excited to announce that the **alpha version** of the LeptonX theme has been released! As stated in [this blog post](https://volosoft.com/blog/introducing-the-lepton-theme-next-generation), LeptonX comes in different shapes. For this release, we introduce only ABP based projects with the Angular UI. So, if you are already using the ABP Framework and Angular as the frontend choice, you can integrate these packages into your project today.
The theme has been deployed with two versions: LeptonX-lite (free) and LeptonX (commercial).
> **Note that this theme currently only works for the *Angular UI*. Please keep waiting for other UI options.**
## Open-Source
This section shows how to replace the basic theme (that comes with open source ABP Framework startup template) with the new LeptonX-lite theme.
To add `LeptonX-lite` into your project,
* Install `@abp/ng.theme.lepton-x` NPM package
`npm install @abp/ng.theme.lepton-x@preview` or
`yarn add @abp/ng.theme.lepton-x@preview`
* Then, we need to edit the styles array in `angular.json` to replace the existing style with the new one.
Replace the following style
```JSON
{
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
"inject": true,
"bundleName": "bootstrap-ltr.min"
},
```
with
```json
"node_modules/@volo/ngx-lepton-x.lite/styles/sidemenu-layout.min.css",
"node_modules/bootstrap-icons/font/bootstrap-icons.css",
```
* Finally, remove `ThemeBasicModule` from `app.module.ts` and `shared.module.ts`, and import the related modules in `app.module.ts`
```js
import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x';
import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts';
@NgModule({
imports: [
// ...
ThemeLeptonXModule.forRoot(),
SideMenuLayoutModule.forRoot(),
],
// ...
})
export class AppModule {}
```
Note: If you employ [Resource Owner Password Flow](https://docs.abp.io/en/abp/latest/UI/Angular/Authorization#resource-owner-password-flow) for authorization, you should import the following module as well:
```js
import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
@NgModule({
// ...
imports: [
// ...
AccountLayoutModule.forRoot(),
// ...
],
// ...
})
export class AppModule {}
```
To change the logos and brand color of the `LeptonX`, simply add the following CSS to the `styles.scss`
```css
:root {
--lpx-logo: url('/assets/images/logo.png');
--lpx-logo-icon: url('/assets/images/logo-icon.png');
--lpx-brand: #edae53;
}
```
- `--lpx-logo` is used to place the logo in the menu.
- `--lpx-logo-icon` is a square icon used when the menu is collapsed.
- `--lpx-brand` is a color used throughout the application, especially on active elements.
![LeptonX-lite dashboard](./lepton-x-lite-dashboard.png)
![LeptonX-lite menu collapsed](./lepton-x-lite-menu-collapsed.png)
## ABP Commercial
This section shows how to replace the lepton theme (that comes with the ABP Commercial startup template) with the new LeptonX theme.
To add `LeptonX` into your existing projects,
* Firstly, install `@volosoft/abp.ng.theme.lepton-x` NPM package
`npm install @volosoft/abp.ng.theme.lepton-x@preview` or
`yarn add @volosoft/abp.ng.theme.lepton-x@preview`
* Then, edit `angular.json` as follows:
Remove the following config from the `styles` array since LeptonX provides bootstrap as embedded in its CSS.
```JSON
{
"input": "node_modules/bootstrap/dist/css/bootstrap.min.css",
"inject": true,
"bundleName": "bootstrap-ltr.min"
},
```
Add the following ones into the `styles` array
```JSON
{
"input": "node_modules/@volosoft/ngx-lepton-x/styles/themes/dark.css",
"inject": false,
"bundleName": "lepton-x.dark"
},
{
"input": "node_modules/@volosoft/ngx-lepton-x/styles/themes/dim.css",
"inject": false,
"bundleName": "lepton-x.dim"
},
{
"input": "node_modules/@volosoft/ngx-lepton-x/styles/themes/light.css",
"inject": false,
"bundleName": "lepton-x.light"
},
"node_modules/@volosoft/ngx-lepton-x/styles/css/sidemenu-layout.min.css",
"node_modules/bootstrap-icons/font/bootstrap-icons.css",
```
Three of them are related to the theming and will be loaded during runtime. That's why they are not injected into the `head` as a style. Hence, the `"inject": false`
The fourth one depends on which layout you want to use. For now, there is only `sidemenu-layout` available. In the future, there will be many layouts to choose from.
The last one is `bootstrap-icons` which are being used throughout the components.
* At last, remove `ThemeLeptonModule` from `app.module.ts` and `shared.module.ts`, and import the following modules in `app.module.ts`
```js
import { ThemeLeptonXModule } from '@volosoft/abp.ng.theme.lepton-x';
import { AbpSideMenuLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/layouts';
@NgModule({
// ...
imports: [
// ...
ThemeLeptonXModule.forRoot(),
AbpSideMenuLayoutModule.forRoot(), // depends on which layout you choose
// ...
],
// ...
})
export class AppModule {}
```
Note: If you employ [Resource Owner Password Flow](https://docs.abp.io/en/abp/latest/UI/Angular/Authorization#resource-owner-password-flow) for authorization, you should import the following module as well:
```js
import { AccountLayoutModule } from '@volosoft/abp.ng.theme.lepton-x/account';
@NgModule({
// ...
imports: [
// ...
AccountLayoutModule.forRoot({
layout: {
authLayoutImg: '/assets/images/login-bg.jpg',
},
}),
// ...
],
// ...
})
export class AppModule {}
```
`authLayoutImg`: (Optional) If not given, a default image will be placed on the authentication pages.
* At this point, `LeptonX` theme should be up and running within your application. However, you may need to overwrite some css variables based your needs for every theme available as follows:
```scss
:root {
.lpx-theme-dark {
--lpx-logo: url('/assets/images/logo/logo-light.svg');
--lpx-logo-icon: url('/assets/images/logo/logo-light-icon.svg');
--lpx-brand: #edae53;
}
.lpx-theme-dim {
--lpx-logo: url('/assets/images/logo/logo-light.svg');
--lpx-logo-icon: url('/assets/images/logo/logo-light-icon.svg');
--lpx-brand: #f15835;
}
.lpx-theme-light {
--lpx-logo: url('/assets/images/logo/logo-dark.svg');
--lpx-logo-icon: url('/assets/images/logo/logo-dark-icon.svg');
--lpx-brand: #69aada;
}
}
```
When the user selects a theme, the corresponding CSS class is added to the `body`, so you can write specific CSS rules to each theme.
## Conclusion
In this blog post, I've explained how to use the alpha version of the new LeptonX theme for ABP-based solutions. Please, keep in mind that this is an alpha version, and we will continue to work on the LeptonX theme. The APIs are bound to change and breaking changes may be introduced in future versions.
We would like you to try it out with the latest version of the ABP Framework and give us feedback at lepton@volosoft.com or open an issue on this repository: https://github.com/volosoft/lepton-theme

BIN
docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
docs/en/Blog-Posts/2021-07-28-lepton-x-release/lepton-x-lite-menu-collapsed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

42
docs/en/Blog-Posts/2021-08-02 v4_4_Release_Stable/POST.md

@ -0,0 +1,42 @@
# ABP.IO Platform 4.4 Final Has Been Released!
[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 4.4 versions have been released today.
## What's New With 4.4?
Since all the new features are already explained in details with the 4.4 RC announcement posts, I will not repeat all the details again. See [the related blog post](https://blog.abp.io/abp/ABP-Platform-4-4-RC-Has-Been-Released) for all the features and enhancements.
## How to Upgrade an Existing Solution
### Install/Update the ABP CLI
First of all, install the ABP CLI or upgrade to the latest version.
If you haven't installed yet:
```bash
dotnet tool install -g Volo.Abp.Cli
```
To update an existing installation:
```bash
dotnet tool update -g Volo.Abp.Cli
```
### ABP UPDATE Command
[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command:
```bash
abp update
```
Run this command in the root folder of your solution.
## The Road Map
The next feature version will be 5.0. It is planned to release the 5.0 RC (Release Candidate) in November 2021. See the updated road maps;
* [ABP Framework Road Map](https://docs.abp.io/en/abp/latest/Road-Map)
* [ABP Commercial Road Map](https://docs.abp.io/en/commercial/latest/road-map)

13
docs/en/CLI.md

@ -161,7 +161,7 @@ abp add-package <package-name> [options]
Example:
````
abp add-package Volo.Abp.MongoDB
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
````
* This example adds the Volo.Abp.MongoDB package to the project.
@ -170,7 +170,14 @@ abp add-package Volo.Abp.MongoDB
* `--project` or `-p`: Specifies the project (.csproj) file path. If not specified, CLI tries to find a .csproj file in the current directory.
* `--with-source-code`: Downloads the source code of the package to your solution folder and uses local project references instead of NuGet/NPM packages.
* `--add-to-solution-file`: Adds the downloaded package to your solution file, so you will also see the package when you open the solution on a IDE. (only available when `--with-source-code` is True.)
* `--add-to-solution-file`: Adds the downloaded package to your solution file, so you will also see the package when you open the solution on a IDE. (only available when `--with-source-code` is True)
> Currently only the source code of the basic theme packages([MVC](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Basic-Theme) and [Blazor](https://docs.abp.io/en/abp/latest/UI/Blazor/Basic-Theme)) can be downloaded.
> - Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
> - Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme
> - Volo.Abp.AspNetCore.Components.Web.BasicTheme
> - Volo.Abp.AspNetCore.Components.Server.BasicTheme
### add-module
@ -454,4 +461,4 @@ abp install-libs [options]
## See Also
* [Examples for the new command](CLI-New-Command-Samples.md)
* [Examples for the new command](CLI-New-Command-Samples.md)

2
docs/en/Community-Articles/2020-05-29-Real-Time-Messaging-In-A-Distributed-Architecture-Using-Abp-Framework-SingalR-RabbitMQ/POST.md

@ -168,7 +168,7 @@ namespace SignalRTieredDemo.Web
{
````
Also, we need to add [@abp/signalr](https://www.npmjs.com/package/@abp/signalr) npm package to package.json in ***.Web** project, then run **yarn** and **gulp** commands.
Also, we need to add [@abp/signalr](https://www.npmjs.com/package/@abp/signalr) npm package to package.json in ***.Web** project, then run **abp install-libs** command.
`````json
{

46
docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md

@ -194,16 +194,11 @@ We implemented token generation infrastructure, now it's time validate the token
```csharp
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Identity;
using Volo.Abp.Security.Claims;
using Volo.Abp.Users;
using Volo.Abp.Identity.AspNetCore;
namespace PasswordlessAuthentication.Web.Controllers
{
@ -211,9 +206,12 @@ namespace PasswordlessAuthentication.Web.Controllers
{
protected IdentityUserManager UserManager { get; }
public PasswordlessController(IdentityUserManager userManager)
protected AbpSignInManager SignInManager { get; }
public PasswordlessController(IdentityUserManager userManager, AbpSignInManager signInManager)
{
UserManager = userManager;
SignInManager = signInManager;
}
public virtual async Task<IActionResult> Login(string token, string userId)
@ -228,45 +226,15 @@ namespace PasswordlessAuthentication.Web.Controllers
await UserManager.UpdateSecurityStampAsync(user);
var roles = await UserManager.GetRolesAsync(user);
var principal = new ClaimsPrincipal(
new ClaimsIdentity(CreateClaims(user, roles), IdentityConstants.ApplicationScheme)
);
await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, principal);
await SignInManager.SignInAsync(user, isPersistent: false);
return Redirect("/");
}
private static IEnumerable<Claim> CreateClaims(IUser user, IEnumerable<string> roles)
{
var claims = new List<Claim>
{
new Claim("sub", user.Id.ToString()),
new Claim(AbpClaimTypes.UserId, user.Id.ToString()),
new Claim(AbpClaimTypes.Email, user.Email),
new Claim(AbpClaimTypes.UserName, user.UserName),
new Claim(AbpClaimTypes.EmailVerified, user.EmailConfirmed.ToString().ToLower()),
};
if (!string.IsNullOrWhiteSpace(user.PhoneNumber))
{
claims.Add(new Claim(AbpClaimTypes.PhoneNumber, user.PhoneNumber));
}
foreach (var role in roles)
{
claims.Add(new Claim(AbpClaimTypes.Role, role));
}
return claims;
}
}
}
```
We created an endpoint for `/Passwordless/Login` that gets the token and the user Id. In this action, we find the user via repository and validate the token via `UserManager.VerifyUserTokenAsync()` method. If it's valid, we create claims of the user then call `HttpContext.SignInAsync` to be able to create an encrypted cookie and add it to the current response. Finally we redirect the page to the root URL.
We created an endpoint for `/Passwordless/Login` that gets the token and the user Id. In this action, we find the user via repository and validate the token via `UserManager.VerifyUserTokenAsync()` method. If it's valid, we call `SignInManager.SignInAsync` to be able to create an encrypted cookie and add it to the current response. Finally we redirect the page to the root URL.
That's all! We created a passwordless login with 7 steps.

6
docs/en/Community-Articles/2020-08-18-Using-DevExtreme-Components-With-The-ABP-Framework/Using-DevExtreme-Components-With-The-ABP-Framework.md

@ -77,9 +77,11 @@ module.exports = {
};
```
Open your `DevExtremeSample.Web` project folder with a command line and run the `gulp` command. This command will copy the needed library files into the ``/wwwroot/libs/devextreme/` folder.
Open your `DevExtremeSample.Web` project folder with a command line and run the `abp install-libs` command. This command will copy the needed library files into the `/wwwroot/libs/devextreme/` folder.
![gulp](gulp.png)
````bash
abp install-libs
````
You can see `devextreme` folder inside the `wwwroot/libs`:

2
docs/en/Community-Articles/2021-03-12-Simple-SignalR-Notification/POST.md

@ -91,7 +91,7 @@ You can install the latest version (3.1.13 will be old)
#### 3- Add resource Mapping
We added SignalR to the `package.json` but it comes into your `node_modules` folder. We need to copy the related files to `wwwroot/libs` folder. To do this copy the content of the following file to your `abp.resourcemappings.js` file. It's in your root directory of Web folder. After you do this, go to your web directory and run `gulp` command. By doing this, it'll copy the related files into your `wwwroot/libs` folder.
We added SignalR to the `package.json` but it comes into your `node_modules` folder. We need to copy the related files to `wwwroot/libs` folder. To do this copy the content of the following file to your `abp.resourcemappings.js` file. It's in your root directory of Web folder. After you do this, go to your web directory and run `abp install-libs` command. By doing this, it'll copy the related files into your `wwwroot/libs` folder.
[abp.resourcemappings.js](https://gist.github.com/ebicoglu/f7dc22cca2d353f8bf7f68a03e3395b8#file-abp-resourcemapping-js)

2
docs/en/Community-Articles/2021-05-24-Removing-EfCore-Migrations/POST.md

@ -30,7 +30,7 @@ If you want to make it in your solution with today, follow the steps in this art
> There is one **drawback** with the new design (everything in software development is a trade-off). We need to remove the `AppUser` entity, because EF Core can't map two classes to single table without an inheritance relation. I will cover this later in this article and provide suggestions to deal with it.
> If you are using **ABP Commercial**, ABP Suite code generation won't work correctly with the new design. In this case, we suggest to wait for the next version.
> If you are using **ABP Commercial**, ABP Suite code generation won't work correctly before the version 4.4. Please upgrade to v4.4 if you are using a previous version.
## The Steps

3
docs/en/Concurrency-Check.md

@ -0,0 +1,3 @@
## Concurrency Check
TODO

8
docs/en/Dapper.md

@ -53,14 +53,16 @@ public class PersonDapperRepository : DapperRepository<MyAppDbContext>, ITransie
public virtual async Task<List<string>> GetAllPersonNames()
{
return (await DbConnection.QueryAsync<string>("select Name from People", transaction: DbTransaction))
var dbConnection = await GetDbConnectionAsync();
return (await dbConnection.QueryAsync<string>("select Name from People", transaction: await GetDbTransactionAsync()))
.ToList();
}
public virtual async Task<int> UpdatePersonNames(string name)
{
return await DbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name },
DbTransaction);
var dbConnection = await GetDbConnectionAsync();
return await dbConnection.ExecuteAsync("update People set Name = @NewName", new { NewName = name },
await GetDbTransactionAsync());
}
}
```

35
docs/en/Data-Filtering.md

@ -239,15 +239,25 @@ protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntit
### MongoDB
ABP implements data filters directly in the [repository](Repositories.md) level for the [MongoDB Integration](MongoDB.md). So, it works only if you use the repositories properly. Otherwise, you should manually filter the data.
ABP abstracts the `IMongoDbRepositoryFilterer` interface to implement data filtering for the [MongoDB Integration](MongoDB.md), it works only if you use the repositories properly. Otherwise, you should manually filter the data.
Currently, the best way to implement a data filter for the MongoDB integration is to override the `AddGlobalFilters` in the repository derived from the `MongoDbRepository` class. Example:
Currently, the best way to implement a data filter for the MongoDB integration is to create a derived class of `MongoDbRepositoryFilterer` and override `AddGlobalFilters`. Example:
````csharp
public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, Guid>
[ExposeServices(typeof(IMongoDbRepositoryFilterer<Book, Guid>))]
public class BookMongoDbRepositoryFilterer : MongoDbRepositoryFilterer<Book, Guid> , ITransientDependency
{
protected override void AddGlobalFilters(List<FilterDefinition<Book>> filters)
public BookMongoDbRepositoryFilterer(
IDataFilter dataFilter,
ICurrentTenant currentTenant) :
base(dataFilter, currentTenant)
{
}
public override void AddGlobalFilters(List<FilterDefinition<Book>> filters)
{
base.AddGlobalFilters(filters);
if (DataFilter.IsEnabled<IIsActive>())
{
filters.Add(Builders<Book>.Filter.Eq(e => ((IIsActive)e).IsActive, true));
@ -256,7 +266,7 @@ public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, G
}
````
This example implements it only for the `Book` entity. If you want to implement for all entities (those implement the `IIsActive` interface), create your own custom MongoDB repository base class and override the `AddGlobalFilters` as shown below:
This example implements it only for the `Book` entity. If you want to implement for all entities (those implement the `IIsActive` interface), create your own custom MongoDB repository filterer base class and override the `AddGlobalFilters` as shown below:
````csharp
public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoDbRepository<TMongoDbContext, TEntity, TKey>
@ -271,6 +281,8 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
protected override void AddGlobalFilters(List<FilterDefinition<TEntity>> filters)
{
base.AddGlobalFilters(filters);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))
&& DataFilter.IsEnabled<IIsActive>())
{
@ -278,6 +290,15 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
}
}
}
````
> See "Set Default Repository Classes" section of the [MongoDb Integration document](MongoDB.md) to learn how to replace default repository base with your custom class.
public class MyMongoDbModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//.......
context.Services
.Replace(ServiceDescriptor.Transient(typeof(IMongoDbRepositoryFilterer<,>),typeof(MyMongoDbRepositoryFilterer<,>)));
}
}
````

8
docs/en/Data-Transfer-Objects.md

@ -210,15 +210,15 @@ namespace AbpDemo
{
//Create the query
var query = _productRepository
.OrderBy(input.Sorting)
.Skip(input.SkipCount)
.Take(input.MaxResultCount);
.OrderBy(input.Sorting);
//Get total count from the repository
var totalCount = await query.CountAsync();
//Get entities from the repository
List<Product> products = await query.ToListAsync();
List<Product> products = await query
.Skip(input.SkipCount)
.Take(input.MaxResultCount).ToListAsync();
//Map entities to DTOs
List<ProductDto> productDtos =

7
docs/en/Modules/Docs.md

@ -185,10 +185,11 @@ Open `package.json` and add `@abp/docs": "^2.9.0` as shown below:
}
```
Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
1. `yarn`
2. `gulp`
````bash
abp install-libs
````
### 4- Database Integration

6
docs/en/Modules/Permission-Management.md

@ -28,7 +28,7 @@ In this dialog, you can grant permissions for the selected role. The tabs in the
## IPermissionManager
`IPermissionManager` is the main service provided by this module. It is used to read and change the permission values. `IPermissionManager` is typically used by the *Feature Management Dialog*. However, you can inject it if you need to set a permission value.
`IPermissionManager` is the main service provided by this module. It is used to read and change the permission values. `IPermissionManager` is typically used by the *Permission Management Dialog*. However, you can inject it if you need to set a permission value.
> If you just want to read/check permission values for the current user, use the `IAuthorizationService` or the `[Authorize]` attribute as explained in the [Authorization document](../Authorization.md).
@ -91,9 +91,9 @@ public class CustomPermissionManagementProvider : PermissionManagementProvider
}
````
`PermissionManagementProvider` base class makes the default implementation (using the `IPermissionGrantRepository`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each feature value record).
`PermissionManagementProvider` base class makes the default implementation (using the `IPermissionGrantRepository`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each permission value record).
Once you create your provider class, you should register it using the `FeatureManagementOptions` [options class](../Options.md):
Once you create your provider class, you should register it using the `PermissionManagementOptions` [options class](../Options.md):
````csharp
Configure<PermissionManagementOptions>(options =>

2
docs/en/Modules/Setting-Management.md

@ -99,7 +99,7 @@ public class CustomSettingProvider : SettingManagementProvider
}
````
`SettingManagementProvider` base class makes the default implementation (using the `ISettingManagementStore`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each feature value record).
`SettingManagementProvider` base class makes the default implementation (using the `ISettingManagementStore`) for you. You can override base methods as you need. Every provider must have a unique name, which is `Custom` in this example (keep it short since it is saved to database for each setting value record).
Once you create your provider class, you should register it using the `SettingManagementOptions` [options class](../Options.md):

5
docs/en/Modules/Virtual-File-Explorer.md

@ -60,8 +60,9 @@ Or you can also manually install nuget package to `Acme.MyProject.Web` project:
Then open the command line terminal in the `Acme.MyProject.Web` project folder and run the following command:
1. `yarn`
2. `gulp`
````bash
abp install-libs
````
That's all,Now run the application and Navigate to `/VirtualFileExplorer`. You will see virtual file explorer page:

9
docs/en/Road-Map.md

@ -10,12 +10,9 @@ This version will focus on the following works:
* Upgrading to .NET 6.0 ([#9004](https://github.com/abpframework/abp/issues/9004))
* Upgrading to Bootstrap 5.x ([#8922](https://github.com/abpframework/abp/issues/8922))
* Alternative to IdentityServer4 ([#7221](https://github.com/abpframework/abp/issues/7221))
* C# and JavaScript Static Client Proxy Generation ([#9864](https://github.com/abpframework/abp/issues/9864))
* Revisit the microservice demo solution ([#8385](https://github.com/abpframework/abp/issues/8385))
* Dapr integration ([#2183](https://github.com/abpframework/abp/issues/2183))
* Publishing distributed events as transactional ([#6126](https://github.com/abpframework/abp/issues/6126))
* Resource based authorization system ([#236](https://github.com/abpframework/abp/issues/236))
* API Versioning system: finalize & document ([#497](https://github.com/abpframework/abp/issues/497))
* Performance optimizations; Enabling .NET Trimming, using source generators and reducing reflection, etc.
* Improving the abp.io platform and work more on contents and documents
@ -27,6 +24,10 @@ The *Next Versions* section above shows the main focus of the planned versions.
Here, a list of major items in the backlog we are considering to work on in the next versions.
* ([#497](https://github.com/abpframework/abp/issues/497)) API Versioning system: finalize & document
* ([#7221](https://github.com/abpframework/abp/issues/7221)) Alternative to IdentityServer4
* ([#2183](https://github.com/abpframework/abp/issues/2183)) Dapr integration
* ([#236](https://github.com/abpframework/abp/issues/236)) Resource based authorization system
* [#2882](https://github.com/abpframework/abp/issues/2882) / Providing a gRPC integration infrastructure (while it is [already possible](https://github.com/abpframework/abp-samples/tree/master/GrpcDemo) to create or consume gRPC endpoints for your application, we plan to create endpoints for the [standard application modules](https://docs.abp.io/en/abp/latest/Modules/Index))
* [#1754](https://github.com/abpframework/abp/issues/1754) / Multi-lingual entities
* [#57](https://github.com/abpframework/abp/issues/57) / Built-in CQRS infrastructure

4
docs/en/SignalR-Integration.md

@ -70,10 +70,10 @@ This will add the `@abp/signalr` to the dependencies in the `package.json` of yo
}
````
Run the `gulp` in the root folder of your web project:
Run the following [ABP CLI](CLI.md) command in the root folder of your web project:
````bash
gulp
abp install-libs
````
This will copy the SignalR JavaScript files into your project:

3
docs/en/Swagger.md

@ -1,3 +0,0 @@
# Swagger UI Integration
TODO

2
docs/en/Text-Templating-Scriban.md

@ -1,4 +1,4 @@
# Razor Integration
# Scriban Integration
## Installation

2
docs/en/Tutorials/Part-9.md

@ -1022,7 +1022,7 @@ Create a new Razor Component Page, `/Pages/Authors.razor`, in the `Acme.BookStor
</Modal>
````
* This code is similar to the `Books.razor`, except it doesn't inherit from the `BlazorisePageBase`, but uses its own implementation.
* This code is similar to the `Books.razor`, except it doesn't inherit from the `AbpCrudPageBase`, but uses its own implementation.
* Injects the `IAuthorAppService` to consume the server side HTTP APIs from the UI. We can directly inject application service interfaces and use just like regular method calls by the help of [Dynamic C# HTTP API Client Proxy System](../API/Dynamic-CSharp-API-Clients.md), which performs REST API calls for us. See the `Authors` class below to see the usage.
* Injects the `IAuthorizationService` to check [permissions](../Authorization.md).
* Injects the `IObjectMapper` for [object to object mapping](../Object-To-Object-Mapping.md).

2
docs/en/Tutorials/Todo/Index.md

@ -618,7 +618,7 @@ Open the `Index.razor` file in the `Pages` folder of the *TodoApp.Blazor* projec
### Index.razor.css
As the final touch, open the `Index.razor.css` file in the `Pages` folder of the *TodoApp.Web* project and replace with the following content:
As the final touch, open the `Index.razor.css` file in the `Pages` folder of the *TodoApp.Blazor* project and replace with the following content:
````css
#TodoList{

67
docs/en/UI/Angular/How-Replaceable-Components-Work-with-Extensions.md

@ -17,30 +17,18 @@ yarn ng generate component my-roles/my-roles --flat --export
Open the generated `src/app/my-roles/my-roles.component.ts` file and replace its content with the following:
```js
import { ListService, PagedAndSortedResultRequestDto } from '@abp/ng.core';
import {
CreateRole,
DeleteRole,
eIdentityComponents,
GetRoleById,
GetRoles,
IdentityRoleDto,
IdentityState,
RolesComponent,
UpdateRole,
} from '@abp/ng.identity';
import { ListService, PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core';
import { eIdentityComponents, IdentityRoleDto, IdentityRoleService, RolesComponent } from '@abp/ng.identity';
import { ePermissionManagementComponents } from '@abp/ng.permission-management';
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared';
import {
EXTENSIONS_IDENTIFIER,
FormPropData,
generateFormFromProps,
generateFormFromProps
} from '@abp/ng.theme.shared/extensions';
import { Component, Injector, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { finalize, pluck } from 'rxjs/operators';
import { finalize } from 'rxjs/operators';
@Component({
selector: 'app-my-roles',
@ -51,15 +39,14 @@ import { finalize, pluck } from 'rxjs/operators';
provide: EXTENSIONS_IDENTIFIER,
useValue: eIdentityComponents.Roles,
},
{ provide: RolesComponent, useExisting: MyRolesComponent },
{
provide: RolesComponent,
useExisting: MyRolesComponent
}
],
})
export class MyRolesComponent implements OnInit {
@Select(IdentityState.getRoles)
data$: Observable<IdentityRoleDto[]>;
@Select(IdentityState.getRolesTotalCount)
totalCount$: Observable<number>;
data: PagedResultDto<IdentityRoleDto> = { items: [], totalCount: 0 };
form: FormGroup;
@ -82,8 +69,8 @@ export class MyRolesComponent implements OnInit {
constructor(
public readonly list: ListService<PagedAndSortedResultRequestDto>,
protected confirmationService: ConfirmationService,
protected store: Store,
protected injector: Injector
protected injector: Injector,
protected service: IdentityRoleService,
) {}
ngOnInit() {
@ -106,25 +93,21 @@ export class MyRolesComponent implements OnInit {
}
edit(id: string) {
this.store
.dispatch(new GetRoleById(id))
.pipe(pluck('IdentityState', 'selectedRole'))
.subscribe(selectedRole => {
this.selected = selectedRole;
this.openModal();
});
this.service.get(id).subscribe(res => {
this.selected = res;
this.openModal();
});
}
save() {
if (!this.form.valid) return;
this.modalBusy = true;
this.store
.dispatch(
this.selected.id
? new UpdateRole({ ...this.selected, ...this.form.value, id: this.selected.id })
: new CreateRole(this.form.value)
)
const { id } = this.selected;
(id
? this.service.update(id, { ...this.selected, ...this.form.value })
: this.service.create(this.form.value)
)
.pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => {
this.isModalVisible = false;
@ -139,13 +122,13 @@ export class MyRolesComponent implements OnInit {
})
.subscribe((status: Confirmation.Status) => {
if (status === Confirmation.Status.confirm) {
this.store.dispatch(new DeleteRole(id)).subscribe(() => this.list.get());
this.service.delete(id).subscribe(() => this.list.get());
}
});
}
private hookToQuery() {
this.list.hookToQuery(query => this.store.dispatch(new GetRoles(query))).subscribe();
this.list.hookToQuery(query => this.service.getList(query)).subscribe(res => (this.data = res));
}
openPermissionsModal(providerKey: string) {
@ -189,15 +172,15 @@ Open the generated `src/app/my-role/my-role.component.html` file and replace its
<h5 class="card-title">My Roles</h5>
</div>
<div class="text-right col col-md-6">
<abp-page-toolbar [record]="data$ | async"></abp-page-toolbar>
<abp-page-toolbar [record]="data.items"></abp-page-toolbar>
</div>
</div>
</div>
<div class="card-body">
<abp-extensible-table
[data]="data$ | async"
[recordsTotal]="totalCount$ | async"
[data]="data.items"
[recordsTotal]="data.totalCount"
[list]="list"
></abp-extensible-table>
</div>

276
docs/en/UI/Angular/Permission-Management-Component-Replacement.md

@ -5,37 +5,27 @@
Run the following command in `angular` folder to create a new component called `PermissionManagementComponent`.
```bash
yarn ng generate component permission-management --entryComponent --inlineStyle
# You don't need the --entryComponent option in Angular 9
yarn ng generate component permission-management --inlineStyle
```
Open the generated `permission-management.component.ts` in `src/app/permission-management` folder and replace the content with the following:
```js
import { ConfigStateService, CurrentUserDto, ReplaceableComponents } from '@abp/ng.core';
import {
GetPermissionListResultDto,
PermissionGrantInfoDto, PermissionGroupDto, PermissionManagement, PermissionsService, ProviderInfoDto, UpdatePermissionDto
} from '@abp/ng.permission-management';
import { LocaleDirection } from '@abp/ng.theme.shared';
import {
Component,
EventEmitter,
Input,
Output,
Renderer2,
TrackByFunction,
Inject,
Optional,
EventEmitter, Inject, Input, Optional, Output, TrackByFunction
} from '@angular/core';
import { ReplaceableComponents } from '@abp/ng.core';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { finalize, map, pluck, take, tap } from 'rxjs/operators';
import {
GetPermissions,
UpdatePermissions,
PermissionManagement,
PermissionManagementState,
} from '@abp/ng.permission-management';
import { of } from 'rxjs';
import { finalize, switchMap, tap } from 'rxjs/operators';
type PermissionWithMargin = PermissionManagement.Permission & {
margin: number;
type PermissionWithStyle = PermissionGrantInfoDto & {
style: string;
};
@Component({
@ -52,8 +42,8 @@ type PermissionWithMargin = PermissionManagement.Permission & {
})
export class PermissionManagementComponent
implements
PermissionManagement.PermissionManagementComponentInputs,
PermissionManagement.PermissionManagementComponentOutputs {
PermissionManagement.PermissionManagementComponentInputs,
PermissionManagement.PermissionManagementComponentOutputs {
protected _providerName: string;
@Input()
get providerName(): string {
@ -115,15 +105,11 @@ export class PermissionManagementComponent
@Output() readonly visibleChange = new EventEmitter<boolean>();
@Select(PermissionManagementState.getPermissionGroups)
groups$: Observable<PermissionManagement.Group[]>;
data: GetPermissionListResultDto = { groups: [], entityDisplayName: null };
@Select(PermissionManagementState.getEntityDisplayName)
entityName$: Observable<string>;
selectedGroup: PermissionGroupDto;
selectedGroup: PermissionManagement.Group;
permissions: PermissionManagement.Permission[] = [];
permissions: PermissionGrantInfoDto[] = [];
selectThisTab = false;
@ -131,25 +117,26 @@ export class PermissionManagementComponent
modalBusy = false;
trackByFn: TrackByFunction<PermissionManagement.Group> = (_, item) => item.name;
get selectedGroupPermissions$(): Observable<PermissionWithMargin[]> {
return this.groups$.pipe(
map((groups) =>
this.selectedGroup
? groups.find((group) => group.name === this.selectedGroup.name).permissions
: []
),
map<PermissionManagement.Permission[], PermissionWithMargin[]>((permissions) =>
permissions.map(
(permission) =>
(({
...permission,
margin: findMargin(permissions, permission),
isGranted: this.permissions.find((per) => per.name === permission.name).isGranted,
} as any) as PermissionWithMargin)
)
)
trackByFn: TrackByFunction<PermissionGroupDto> = (_, item) => item.name;
get selectedGroupPermissions(): PermissionWithStyle[] {
if (!this.selectedGroup) return [];
const margin = `margin-${
(document.body.dir as LocaleDirection) === 'rtl' ? 'right' : 'left'
}.px`;
const permissions = this.data.groups.find(
group => group.name === this.selectedGroup.name,
).permissions;
return permissions.map(
permission =>
({
...permission,
style: { [margin]: findMargin(permissions, permission) },
isGranted: this.permissions.find(per => per.name === permission.name).isGranted,
} as unknown as PermissionWithStyle),
);
}
@ -166,21 +153,22 @@ export class PermissionManagementComponent
PermissionManagement.PermissionManagementComponentInputs,
PermissionManagement.PermissionManagementComponentOutputs
>,
private store: Store
private service: PermissionsService,
private configState: ConfigStateService
) {}
getChecked(name: string) {
return (this.permissions.find((per) => per.name === name) || { isGranted: false }).isGranted;
return (this.permissions.find(per => per.name === name) || { isGranted: false }).isGranted;
}
isGrantedByOtherProviderName(grantedProviders: PermissionManagement.GrantedProvider[]): boolean {
isGrantedByOtherProviderName(grantedProviders: ProviderInfoDto[]): boolean {
if (grantedProviders.length) {
return grantedProviders.findIndex((p) => p.providerName !== this.providerName) > -1;
return grantedProviders.findIndex(p => p.providerName !== this.providerName) > -1;
}
return false;
}
onClickCheckbox(clickedPermission: PermissionManagement.Permission, value) {
onClickCheckbox(clickedPermission: PermissionGrantInfoDto, value) {
if (
clickedPermission.isGranted &&
this.isGrantedByOtherProviderName(clickedPermission.grantedProviders)
@ -188,7 +176,7 @@ export class PermissionManagementComponent
return;
setTimeout(() => {
this.permissions = this.permissions.map((per) => {
this.permissions = this.permissions.map(per => {
if (clickedPermission.name === per.name) {
return { ...per, isGranted: !per.isGranted };
} else if (clickedPermission.name === per.parentName && clickedPermission.isGranted) {
@ -206,24 +194,22 @@ export class PermissionManagementComponent
}
setTabCheckboxState() {
this.selectedGroupPermissions$.pipe(take(1)).subscribe((permissions) => {
const selectedPermissions = permissions.filter((per) => per.isGranted);
const element = document.querySelector('#select-all-in-this-tabs') as any;
if (selectedPermissions.length === permissions.length) {
element.indeterminate = false;
this.selectThisTab = true;
} else if (selectedPermissions.length === 0) {
element.indeterminate = false;
this.selectThisTab = false;
} else {
element.indeterminate = true;
}
});
const selectedPermissions = this.selectedGroupPermissions.filter(per => per.isGranted);
const element = document.querySelector('#select-all-in-this-tabs') as any;
if (selectedPermissions.length === this.selectedGroupPermissions.length) {
element.indeterminate = false;
this.selectThisTab = true;
} else if (selectedPermissions.length === 0) {
element.indeterminate = false;
this.selectThisTab = false;
} else {
element.indeterminate = true;
}
}
setGrantCheckboxState() {
const selectedAllPermissions = this.permissions.filter((per) => per.isGranted);
const selectedAllPermissions = this.permissions.filter(per => per.isGranted);
const checkboxElement = document.querySelector('#select-all-in-all-tabs') as any;
if (selectedAllPermissions.length === this.permissions.length) {
@ -238,26 +224,24 @@ export class PermissionManagementComponent
}
onClickSelectThisTab() {
this.selectedGroupPermissions$.pipe(take(1)).subscribe((permissions) => {
permissions.forEach((permission) => {
if (permission.isGranted && this.isGrantedByOtherProviderName(permission.grantedProviders))
return;
const index = this.permissions.findIndex((per) => per.name === permission.name);
this.permissions = [
...this.permissions.slice(0, index),
{ ...this.permissions[index], isGranted: !this.selectThisTab },
...this.permissions.slice(index + 1),
];
});
this.selectedGroupPermissions.forEach(permission => {
if (permission.isGranted && this.isGrantedByOtherProviderName(permission.grantedProviders))
return;
const index = this.permissions.findIndex(per => per.name === permission.name);
this.permissions = [
...this.permissions.slice(0, index),
{ ...this.permissions[index], isGranted: !this.selectThisTab },
...this.permissions.slice(index + 1),
];
});
this.setGrantCheckboxState();
}
onClickSelectAll() {
this.permissions = this.permissions.map((permission) => ({
this.permissions = this.permissions.map(permission => ({
...permission,
isGranted:
this.isGrantedByOtherProviderName(permission.grantedProviders) || !this.selectAllTab,
@ -266,43 +250,41 @@ export class PermissionManagementComponent
this.selectThisTab = !this.selectAllTab;
}
onChangeGroup(group: PermissionManagement.Group) {
onChangeGroup(group: PermissionGroupDto) {
this.selectedGroup = group;
this.setTabCheckboxState();
}
submit() {
this.modalBusy = true;
const unchangedPermissions = getPermissions(
this.store.selectSnapshot(PermissionManagementState.getPermissionGroups)
);
const unchangedPermissions = getPermissions(this.data.groups);
const changedPermissions: PermissionManagement.MinimumPermission[] = this.permissions
.filter((per) =>
unchangedPermissions.find((unchanged) => unchanged.name === per.name).isGranted ===
const changedPermissions: UpdatePermissionDto[] = this.permissions
.filter(per =>
unchangedPermissions.find(unchanged => unchanged.name === per.name).isGranted ===
per.isGranted
? false
: true
: true,
)
.map(({ name, isGranted }) => ({ name, isGranted }));
if (changedPermissions.length) {
this.store
.dispatch(
new UpdatePermissions({
providerKey: this.providerKey,
providerName: this.providerName,
permissions: changedPermissions,
})
)
.pipe(finalize(() => (this.modalBusy = false)))
.subscribe(() => {
this.visible = false;
});
} else {
this.modalBusy = false;
if (!changedPermissions.length) {
this.visible = false;
return;
}
this.modalBusy = true;
this.service
.update(this.providerName, this.providerKey, { permissions: changedPermissions })
.pipe(
switchMap(() =>
this.shouldFetchAppConfig() ? this.configState.refreshAppState() : of(null),
),
finalize(() => (this.modalBusy = false)),
)
.subscribe(() => {
this.visible = false;
});
}
openModal() {
@ -310,20 +292,13 @@ export class PermissionManagementComponent
throw new Error('Provider Key and Provider Name are required.');
}
return this.store
.dispatch(
new GetPermissions({
providerKey: this.providerKey,
providerName: this.providerName,
})
)
.pipe(
pluck('PermissionManagementState', 'permissionRes'),
tap((permissionRes: PermissionManagement.Response) => {
this.selectedGroup = permissionRes.groups[0];
this.permissions = getPermissions(permissionRes.groups);
})
);
return this.service.get(this.providerName, this.providerKey).pipe(
tap((permissionRes: GetPermissionListResultDto) => {
this.data = permissionRes;
this.selectedGroup = permissionRes.groups[0];
this.permissions = getPermissions(permissionRes.groups);
}),
);
}
initModal() {
@ -331,6 +306,13 @@ export class PermissionManagementComponent
this.setGrantCheckboxState();
}
getAssignedCount(groupName: string) {
return this.permissions.reduce(
(acc, val) => (val.name.split('.')[0] === groupName && val.isGranted ? acc + 1 : acc),
0,
);
}
onVisibleChange(visible: boolean) {
this.visible = visible;
@ -339,13 +321,20 @@ export class PermissionManagementComponent
this.replaceableData.outputs.visibleChange(visible);
}
}
shouldFetchAppConfig() {
const currentUser = this.configState.getOne('currentUser') as CurrentUserDto;
if (this.providerName === 'R') return currentUser.roles.some(role => role === this.providerKey);
if (this.providerName === 'U') return currentUser.id === this.providerKey;
return false;
}
}
function findMargin(
permissions: PermissionManagement.Permission[],
permission: PermissionManagement.Permission
) {
const parentPermission = permissions.find((per) => per.name === permission.parentName);
function findMargin(permissions: PermissionGrantInfoDto[], permission: PermissionGrantInfoDto) {
const parentPermission = permissions.find(per => per.name === permission.parentName);
if (parentPermission && parentPermission.parentName) {
let margin = 20;
@ -355,7 +344,7 @@ function findMargin(
return parentPermission ? 20 : 0;
}
function getPermissions(groups: PermissionManagement.Group[]): PermissionManagement.Permission[] {
function getPermissions(groups: PermissionGroupDto[]): PermissionGrantInfoDto[] {
return groups.reduce((acc, val) => [...acc, ...val.permissions], []);
}
```
@ -363,16 +352,12 @@ function getPermissions(groups: PermissionManagement.Group[]): PermissionManagem
Open the generated `permission-management.component.html` in `src/app/permission-management` folder and replace the content with the below:
```html
<abp-modal
[visible]="isVisible"
(visibleChange)="onVisibleChange($event)"
(init)="initModal()"
[busy]="modalBusy"
>
<ng-container *ngIf="{ entityName: entityName$ | async } as data">
<abp-modal [visible]="isVisible" (visibleChange)="onVisibleChange($event)" [busy]="modalBusy">
<ng-container *ngIf="data.entityDisplayName">
<ng-template #abpHeader>
<h4>
{%{{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}}%} - {%{{{ data.entityName }}}%}
{%{{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}}%} -
{%{{{ data.entityDisplayName }}}%}
</h4>
</ng-template>
<ng-template #abpBody>
@ -394,13 +379,18 @@ Open the generated `permission-management.component.html` in `src/app/permission
<div class="row">
<div class="overflow-scroll col-md-4">
<ul class="nav nav-pills flex-column">
<li *ngFor="let group of groups$ | async; trackBy: trackByFn" class="nav-item">
<li *ngFor="let group of data.groups; trackBy: trackByFn" class="nav-item">
<a
*ngIf="{ assignedCount: getAssignedCount(group.name) } as count"
class="nav-link pointer"
[class.active]="selectedGroup?.name === group?.name"
(click)="onChangeGroup(group)"
>{%{{{ group?.displayName }}}%}</a
>
<div [class.font-weight-bold]="count.assignedCount">
{%{{{ group?.displayName }}}%}
<span>({%{{{ count.assignedCount }}}%})</span>
</div>
</a>
</li>
</ul>
</div>
@ -423,12 +413,8 @@ Open the generated `permission-management.component.html` in `src/app/permission
</div>
<hr class="mb-3" />
<div
*ngFor="
let permission of selectedGroupPermissions$ | async;
let i = index;
trackBy: trackByFn
"
[style.margin-left]="permission.margin + 'px'"
*ngFor="let permission of selectedGroupPermissions; let i = index; trackBy: trackByFn"
[ngStyle]="permission.style"
class="custom-checkbox custom-control mb-2"
>
<input

2
docs/en/UI/Angular/Settings.md

@ -2,7 +2,7 @@
You can get settings on the client-side using the [config state service](./Config-State.md) if they are allowed by their setting definition on the server-side.
> This document only explains how settings work in the Angular UI projects. See the [settings document](../../../Settings.md) to understand the ABP setting system.
> This document only explains how settings work in the Angular UI projects. See the [settings document](../../Settings.md) to understand the ABP setting system.
## Before Use

4
docs/en/UI/AspNetCore/Basic-Theme.md

@ -15,7 +15,7 @@ The Basic Theme has RTL (Right-to-Left language) support.
* Install the [Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic) NuGet package to your web project.
* Add `AbpAspNetCoreMvcUiBasicThemeModule` into the `[DependsOn(...)]` attribute for your [module class](../../Module-Development-Basics.md) in the web project.
* Install the [@abp/aspnetcore.mvc.ui.theme.basic](https://www.npmjs.com/package/@abp/aspnetcore.mvc.ui.theme.basic) NPM package to your web project (e.g. `npm install @abp/aspnetcore.mvc.ui.theme.basic` or `yarn add @abp/aspnetcore.mvc.ui.theme.basic`).
* Run `gulp` command in a command line terminal in the web project's folder.
* Run `abp install-libs` command in a command line terminal in the web project's folder.
## Layouts
@ -85,7 +85,7 @@ See the [User Interface Customization Guide](Customization-User-Interface.md) to
You can run the following [ABP CLI](../../CLI.md) command in **Web** project directory to copy the source code to your solution:
`abp add-package Volo.Abp.AspNetCore.Components.Server.BasicTheme --with-source-code --add-to-solution-file`
`abp add-module Volo.BasicTheme --with-source-code --add-to-solution-file`
----

16
docs/en/UI/AspNetCore/Client-Side-Package-Management.md

@ -18,7 +18,7 @@ To solve the versioning problem, we created a **standard set of packages** those
The benefit of a **standard package** is:
* It depends on a **standard version** of a package. Depending on this package is **safe** because all modules depend on the same version.
* It contains the gulp task to copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more.
* It contains the mappings copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more.
Depending on a standard package is easy. Just add it to your **package.json** file like you normally do. Example:
@ -61,7 +61,7 @@ Using NPM packages and NPM/Yarn tool is the de facto standard for client side li
Next challenge is copying needed resources (js, css, img... files) from the `node_modules` into a folder inside the **wwwroot** folder to make it accessible to the clients/browsers.
ABP defines a [Gulp](https://gulpjs.com/) based task to **copy resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
ABP CLI's `abp install-libs` command **copies resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
The **startup templates** are already configured to work all these out of the box. This section will explain the configuration options.
@ -100,17 +100,15 @@ mappings: {
}
````
#### Using The Gulp
#### install-libs Command
Once you properly configure the `abp.resourcemapping.js` file, you can run the gulp command from the command line:
Once you properly configure the `abp.resourcemapping.js` file, you can run the following ABP CLI command from the command line:
````bash
abp install-libs
````
gulp
````
When you run the `gulp`, all packages will copy their own resources into the **wwwroot/libs** folder. Running `yarn & gulp` is only necessary if you make a change in your dependencies in the **package.json** file.
> When you run the Gulp command, dependencies of the application are resolved using the package.json file. The Gulp task automatically discovers and maps all resources from all dependencies (recursively).
When you run this command, all packages will copy their own resources into the **wwwroot/libs** folder. Running `abp install-libs` is only necessary if you make a change in your dependencies in the **package.json** file.
#### See Also

4
docs/en/UI/Blazor/Customization-Overriding-Components.md

@ -20,11 +20,11 @@ First, create your logo and place under a folder in your web application. We use
![bookstore-logo-blazor](../../images/bookstore-logo-blazor.png)
The next step is to create a razor component, like `MyBlazor.razor`, in your application:
The next step is to create a razor component, like `MyBranding.razor`, in your application:
![bookstore-logo-blazor](../../images/bookstore-branding-blazor.png)
The content of the `MyBlazor.razor` is shown below:
The content of the `MyBranding.razor` is shown below:
````html
@using Volo.Abp.DependencyInjection

7
docs/en/Validation.md

@ -149,8 +149,8 @@ Once ABP determines a validation error, it throws an exception of type `AbpValid
In addition to the automatic validation, you may want to manually validate an object. In this case, [inject](Dependency-Injection.md) and use the `IObjectValidator` service:
* `Validate` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state.
* `GetErrors` doesn't throw an exception, but only returns the validation errors.
* `ValidateAsync` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state.
* `GetErrorsAsync` doesn't throw an exception, but only returns the validation errors.
`IObjectValidator` is implemented by the `ObjectValidator` by default. `ObjectValidator` is extensible; you can implement `IObjectValidationContributor` interface to contribute a custom logic. Example:
@ -158,13 +158,14 @@ In addition to the automatic validation, you may want to manually validate an ob
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
public void AddErrors(ObjectValidationContext context)
public Task AddErrorsAsync(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
return Task.CompletedTask;
}
}
````

4
docs/en/docs-nav.json

@ -578,6 +578,10 @@
"path": "API/Application-Configuration.md"
}
]
},
{
"text": "Swagger Integration",
"path": "API/Swagger-Integration.md"
}
]
},

33
docs/zh-Hans/Data-Filtering.md

@ -188,15 +188,25 @@ protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntit
### MongoDB
ABP直接在[仓储](Repositories.md)级别实现数据过滤用于[MongoDB 集成](MongoDB.md). 所以只有正确的使用仓储,它才会工作. 否则你需要手动过滤数据.
ABP抽象了 `IMongoDbRepositoryFilterer` 接口为[MongoDB 集成](MongoDB.md)实现数据过滤, 只有正确的使用仓储,它才会工作. 否则你需要手动过滤数据.
目前为MongoDB集成实现数据过滤的最佳方法是重写派生自 `MongoDbRepository` 仓储`AddGlobalFilters` 方法:
目前为MongoDB集成实现数据过滤的最佳方法是重写派生自 `MongoDbRepositoryFilterer` 基类`AddGlobalFilters` 方法:
````csharp
public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, Guid>
[ExposeServices(typeof(IMongoDbRepositoryFilterer<Book, Guid>))]
public class BookMongoDbRepositoryFilterer : MongoDbRepositoryFilterer<Book, Guid> , ITransientDependency
{
protected override void AddGlobalFilters(List<FilterDefinition<Book>> filters)
public BookMongoDbRepositoryFilterer(
IDataFilter dataFilter,
ICurrentTenant currentTenant) :
base(dataFilter, currentTenant)
{
}
public override void AddGlobalFilters(List<FilterDefinition<Book>> filters)
{
base.AddGlobalFilters(filters);
if (DataFilter.IsEnabled<IIsActive>())
{
filters.Add(Builders<Book>.Filter.Eq(e => ((IIsActive)e).IsActive, true));
@ -205,7 +215,7 @@ public class BookRepository : MongoDbRepository<BookStoreMongoDbContext, Book, G
}
````
示例中仅为 `Book` 实体实现了过滤. 如果你想要为所有的实体实现过滤 (实现了 `IIsActive` 接口的实体),可以创建自己的MongoDB仓储基类并重 写 `AddGlobalFilters` 方法. 如下所示:
示例中仅为 `Book` 实体实现了过滤. 如果你想要为所有的实体实现过滤 (实现了 `IIsActive` 接口的实体),可以创建自己的 `MongoDbRepositoryFilterer` 基类并重 写 `AddGlobalFilters` 方法. 如下所示:
````csharp
public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoDbRepository<TMongoDbContext, TEntity, TKey>
@ -220,6 +230,8 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
protected override void AddGlobalFilters(List<FilterDefinition<TEntity>> filters)
{
base.AddGlobalFilters(filters);
if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))
&& DataFilter.IsEnabled<IIsActive>())
{
@ -227,6 +239,17 @@ public abstract class MyMongoRepository<TMongoDbContext, TEntity, TKey> : MongoD
}
}
}
public class MyMongoDbModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
//.......
context.Services
.Replace(ServiceDescriptor.Transient(typeof(IMongoDbRepositoryFilterer<,>),typeof(MyMongoDbRepositoryFilterer<,>)));
}
}
````
> 参阅[MongoDb集成文档](MongoDB.md)的 "设置默认仓储" 部分了解如何使用自定义类替换默认仓储.

8
docs/zh-Hans/Data-Transfer-Objects.md

@ -210,15 +210,15 @@ namespace AbpDemo
{
//Create the query
var query = _productRepository
.OrderBy(input.Sorting)
.Skip(input.SkipCount)
.Take(input.MaxResultCount);
.OrderBy(input.Sorting);
//Get total count from the repository
var totalCount = await query.CountAsync();
//Get entities from the repository
List<Product> products = await query.ToListAsync();
List<Product> products = await query
.Skip(input.SkipCount)
.Take(input.MaxResultCount);.ToListAsync();
//Map entities to DTOs
List<ProductDto> productDtos =

2
docs/zh-Hans/Entities.md

@ -211,7 +211,7 @@ public class OrderLine : Entity
> 如果你不想你的聚合根继承`AggregateRoot<TKey>`类,你可以直接实现`IAggregateRoot<TKey>`接口
`Order`是一个具有`Guid`类型`Id`属性的 **聚合根**.它有一个`OrderLine`实体集合.`OrderLine`是一个具有组合键(`OrderLine`和 ` ProductId`)的实体.
`Order`是一个具有`Guid`类型`Id`属性的 **聚合根**.它有一个`OrderLine`实体集合.`OrderLine`是一个具有组合键(`OrderId`和 ` ProductId`)的实体.
虽然这个示例可能无法实现聚合根的所有最佳实践,但它仍然遵循良好的实践:

5
docs/zh-Hans/Modules/Docs.md

@ -186,8 +186,9 @@ ABP框架的[文档](docs.abp.io)也是使用的此模块.
然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令:
1. `yarn`
2. `gulp`
````bash
abp install-libs
````
### 4- 数据库集成

5
docs/zh-Hans/Modules/Virtual-File-Explorer.md

@ -60,8 +60,9 @@
然后在 `Acme.MyProject.Web` 项目目录打开命令行终端运行以下命令:
1. `yarn`
2. `gulp`
````bash
abp install-libs
````
这就是全部,运行应用程序导航到 `/VirtualFileExplorer`. 你会看到虚拟文件浏览器页面:

4
docs/zh-Hans/SignalR-Integration.md

@ -70,10 +70,10 @@ yarn add @abp/signalr
}
````
在你的Web项目的根文件夹中运行 `gulp`:
在你的Web项目的根文件夹中运行 `abp install-libs`:
````bash
gulp
abp install-libs
````
它会将SignalR JavaScript文件拷贝到你的项目:

830
docs/zh-Hans/Tutorials/Todo/Index.md

@ -0,0 +1,830 @@
# 快速入门
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"]
}
````
这是一个由单个部分组成的快速入门教程, 旨在使用ABP框架构建一个简单的待办事项应用程序. 这是最终应用程序的屏幕截图:
![待办事项列表](todo-list.png)
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)找到已完成的项目源代码.
## 先决条件
* 一个集成开发环境 (比如: [Visual Studio](https://visualstudio.microsoft.com/vs/)) 它需要支持 [.NET 5.0+](https://dotnet.microsoft.com/download/dotnet) 的开发.
{{if DB=="Mongo"}}
* [MongoDB Server 4.0+](https://docs.mongodb.com/manual/administration/install-community/)
{{end}}
{{if UI=="NG"}}
* [Node v14.x](https://nodejs.org/)
{{end}}
## 创建新的解决方案
我们将使用[ABP CLI](../../CLI.md) 创建带有ABP框架的新解决方案. 你可以在命令行终端中运行以下命令来安装它:
````bash
dotnet tool install -g Volo.Abp.Cli
````
然后创建一个空文件夹, 打开命令行终端并在终端中执行以下命令:
````bash
abp new TodoApp{{if UI=="Blazor"}} -u blazor{{else if UI=="BlazorServer"}} -u blazor-server{{else if UI=="NG"}} -u angular{{end}}{{if DB=="Mongo"}} -d mongodb{{end}}
````
{{if UI=="NG"}}
这将创建一个名为*TodoApp*的新解决方案, 其中包含`angular`和`aspnet core`文件夹. 一旦解决方案就绪, 请在你最喜欢的 IDE 中打开 ASP.NET Core 解决方案.
{{else}}
这将创建一个名为*TodoApp*的新解决方案. 一旦解决方案就绪, 请在你最喜欢的 IDE 中打开它.
{{end}}
### 创建数据库
如果你使用的是Visual Studio, 请右键单击`TodoApp.DbMigrator`项目, 选择*设置为启动项目*, 然后按*Ctrl+F5*运行它而不进行调试. 它将创建初始数据库并生成初始数据.
{{if DB=="EF"}}
> 一些IDE (例如Rider) 可能会在第一次运行时遇到问题, 因为 *DbMigrator* 添加初始迁移并重新编译项目. 在这种情况下, 在 `.DbMigrator` 项目文件夹中打开命令行终端并执行 `dotnet run` 命令.
{{end}}
### 运行应用程序
{{if UI=="MVC" || UI=="BlazorServer"}}
最好在开始开发之前运行一下应用程序. 确保 {{if UI=="BlazorServer"}}`TodoApp.Blazor`{{else}}`TodoApp.Web`{{end}} 是启动项目, 然后运行应用程序(Visual Studio中是Ctrl+F5)来查看初始UI:
{{else if UI=="Blazor"}}
最好在开始开发之前运行一下应用程序. 解决方案中有两个主要应用程序
* `TodoApp.HttpApi.Host` 承载服务器端的 HTTP API.
* `TodoApp.Blazor` 是客户端的Blazor WebAssembly应用程序.
确保 `TodoApp.HttpApi.Host` 是启动项目, 然后运行应用程序(Visual Studio中的Ctrl+F5)打开[Swagger UI](https://swagger.io/tools/swagger-ui/)来查看服务器端的 HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用此 UI 探索和测试你的 HTTP API. 现在, 我们可以将 `TodoApp.Blazor` 设置为启动项目并运行它来打开实际的 Blazor 应用程序UI:
{{else if UI=="NG"}}
最好在开始开发之前运行一下应用程序. 解决方案中有两个主要应用程序;
* `TodoApp.HttpApi.Host` (在.NET解决方案中)承载服务器端HTTP API.
* `Angular` 文件夹包含 Angular 应用程序.
确保 `TodoApp.HttpApi.Host` 是启动项目, 然后运行应用程序(Visual Studio中的Ctrl+F5)打开[Swagger UI](https://swagger.io/tools/swagger-ui/)来查看服务器端的 HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用此 UI 探索和测试你的 HTTP API. 如果该功能正常, 我们可以运行Angular 客户端应用程序.
首先, 运行以下命令来还原NPM包:
````bash
npm install
````
安装所有软件包需要一些时间. 然后可以使用以下命令运行应用程序:
````bash
npm start
````
此命令需要时间, 但最终在你的默认浏览器中运行并打开应用程序:
{{end}}
![todo-ui-initial](todo-ui-initial.png)
你可以单击 *登录* 按钮, 以`admin`作为用户名和`1q2w3E*` 作为密码登录到应用程序.
一切就绪. 我们可以开始编程!
## 领域层
此应用程序只有一个 [实体](../../Entities.md), 接下来我们开始创建它. 在 *TodoApp.Domain* 项目中创建一个新的 `TodoItem` 类:
````csharp
using System;
using Volo.Abp.Domain.Entities;
namespace TodoApp
{
public class TodoItem : BasicAggregateRoot<Guid>
{
public string Text { get; set; }
}
}
````
`BasicAggregateRoot` 是创建根实体的最简单的基础类. `Guid` 是这里实体的主键 (`Id`).
## 数据库集成
{{if DB=="EF"}}
下一步是设置 [Entity Framework Core](../../Entity-Framework-Core.md)配置
### 映射配置
打开在 *TodoApp.EntityFrameworkCore* 项目中 `EntityFrameworkCore` 文件夹中的 `TodoAppDbContext` 类, 并向该类添加新的 `DbSet` 属性:
````csharp
public DbSet<TodoItem> TodoItems { get; set; }
````
然后在 `TodoAppDbContext` 类中定位到 `OnModelCreating` 方法, 并为 `TodoItem` 实体添加映射代码:
````csharp
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
...
/* Configure your own tables/entities inside here */
builder.Entity<TodoItem>(b =>
{
b.ToTable("TodoItems");
});
}
````
我们已经将 `TodoItem` 实体映射到数据库中的 `TodoItems` 表.
### Code First 迁移
解决方案快速模版已经配置为使用Entity Framework Core的 [Code First 迁移](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations). 由于我们已经更改了数据库映射配置, 因此我们应该创建一个新的迁移并将更改应用于数据库.
*TodoApp.EntityFrameworkCore* 项目目录中打开一个命令行终端并输入以下命令:
````bash
dotnet ef migrations add Added_TodoItem
````
这将向项目添加一个新的迁移类:
![todo-efcore-migration](todo-efcore-migration.png)
你可以在同一命令行终端中使用以下命令将更改应用于数据库:
````bash
dotnet ef database update
````
> 如果你使用的是Visual Studio, 则可能希望在 *包管理器控制台 (PMC)* 中使用 `Add-Migration Added_TodoItem``Update-Database` 命令. 在这种情况下, 请确保 {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} 是启动项目, 并且 `TodoApp.EntityFrameworkCore` 是PMC中的 *默认项目*.
{{else if DB=="Mongo"}}
下一步是设置 [MongoDB](../../MongoDB.md) 配置. 打开 *TodoApp.MongoDB* 项目中 `MongoDb` 文件夹的`TodoAppMongoDbContext` 类并做出以下更改;
1. 向类添加新属性:
````csharp
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>();
````
2. 在 `CreateModel` 方法中添加以下代码:
````csharp
modelBuilder.Entity<TodoItem>(b =>
{
b.CollectionName = "TodoItems";
});
````
{{end}}
现在, 我们可以使用ABP仓库保存和检索待办事项, 如我们在下一节所做的那样.
## 应用层
[应用程序服务](../../Application-Services.md) 用于执行应用程序的用例. 我们需要执行以下用例:
* 获取待办事项列表
* 创建新的待办事项
* 删除现有的待办事项
### 应用服务接口
我们可以先从为应用程序服务定义接口开始. 在 *TodoApp.Application.Contracts* 项目中创建新的 `ITodoAppService` 接口, 如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace TodoApp
{
public interface ITodoAppService : IApplicationService
{
Task<List<TodoItemDto>> GetListAsync();
Task<TodoItemDto> CreateAsync(string text);
Task DeleteAsync(Guid id);
}
}
````
### 数据传输对象
`GetListAsync` 和`CreateAsync` 方法返回 `TodoItemDto`. `应用程序服务` 通常获取并返回 DTO([数据传输对象](../../Data-Transfer-Objects.md)) 而不是实体. 因此, 我们应该在这里定义DTO类. 在 *TodoApp.Application.Contracts* 项目中创建新的 `TodoItemDto` 类:
````csharp
using System;
namespace TodoApp
{
public class TodoItemDto
{
public Guid Id { get; set; }
public string Text { get; set; }
}
}
````
这是一个非常简单的DTO类, 它与我们的 `TodoItem` 实体相对应. 接下来, 我们准备实现 `ITodoAppService`接口.
### 应用服务实现
*TodoApp.Application* 项目中创建 `TodoAppService` 类, 如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace TodoApp
{
public class TodoAppService : ApplicationService, ITodoAppService
{
private readonly IRepository<TodoItem, Guid> _todoItemRepository;
public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository)
{
_todoItemRepository = todoItemRepository;
}
// TODO: Implement the methods here...
}
}
````
该类继承自ABP框架的`ApplicationService`类, 并实现了之前定义的 `ITodoAppService`接口. ABP为实体提供默认的泛型 [仓储](../../Repositories.md). 我们可以使用它们来执行基本的数据库操作. 此类中 [注入](../../Dependency-Injection.md) 的 `IRepository<TodoItem, Guid>`, 它就是 `TodoItem` 实体的默认存储库. 我们将使用它来实现之前描述的用例.
#### 获取待办事项
让我们先实现 `GetListAsync` 方法:
````csharp
public async Task<List<TodoItemDto>> GetListAsync()
{
var items = await _todoItemRepository.GetListAsync();
return items
.Select(item => new TodoItemDto
{
Id = item.Id,
Text = item.Text
}).ToList();
}
````
我们只是从数据库中获取完整的`TodoItem`列表, 将它们映射到`TodoItemDto`对象并作为结果返回.
#### 创建一个新的待办事项
下一个我们可以实现方法是 `CreateAsync` , 如下所示:
````csharp
public async Task<TodoItemDto> CreateAsync(string text)
{
var todoItem = await _todoItemRepository.InsertAsync(
new TodoItem {Text = text}
);
return new TodoItemDto
{
Id = todoItem.Id,
Text = todoItem.Text
};
}
````
仓储的 `InsertAsync` 方法将给定的`TodoItem`插入数据库, 并返回相同的`TodoItem` 对象. 它还设置了`Id`, 因此我们可以在返回对象上使用它. 我们只是通过从新的 `TodoItem` 实体创建和返回 `TodoItemDto`.
#### 删除待办事项
最后, 我们来实现 `DeleteAsync` 方法, 代码如下:
````csharp
public async Task DeleteAsync(Guid id)
{
await _todoItemRepository.DeleteAsync(id);
}
````
至此, 应用程序服务已准备好了让UI层来使用.
## 用户界面层
现在是在UI上显示待办事项的时候了! 在开始编写代码之前, 最好记住我们正在尝试构建的内容. 这里是示例程序的最终用户界面的截图:
![待办事项列表](todo-list.png)
> **我们将在本教程中保持最简洁的UI端, 以使本教程简单且重点突出. 请参阅 [web应用程序开发教程](../Part-1.md) 来了解构建实际应用各个方面.**
{{if UI=="MVC"}}
### Index.cshtml.cs
打开在 *TodoApp.Web* 项目的 `Pages` 文件夹中`Index.cshtml.cs`文件, 并用以下代码块替换它的默认内容:
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Web.Pages
{
public class IndexModel : TodoAppPageModel
{
public List<TodoItemDto> TodoItems { get; set; }
private readonly ITodoAppService _todoAppService;
public IndexModel(ITodoAppService todoAppService)
{
_todoAppService = todoAppService;
}
public async Task OnGetAsync()
{
TodoItems = await _todoAppService.GetListAsync();
}
}
}
````
此类使用 `ITodoAppService` 获取待办事项列表并将它赋值给 `TodoItems` 属性. 我们将用它来渲染razor页面上的待办事项目列表.
### Index.cshtml
打开 *TodoApp.Web* 项目中`Pages`文件夹下的`Index.cshtml`, 并替换为以下内容:
````xml
@page
@model TodoApp.Web.Pages.IndexModel
@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>
TODO LIST
</abp-card-title>
</abp-card-header>
<abp-card-body>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm" class="form-inline">
<input id="NewItemText"
type="text"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in Model.TodoItems)
{
<li data-id="@todoItem.Id">
<i class="fa fa-trash-o"></i> @todoItem.Text
</li>
}
</ul>
</abp-card-body>
</abp-card>
</div>
````
我们使用 ABP 的 [卡片标签助手](../../UI/AspNetCore/Tag-Helpers/Cards.md) 来创建一个简单的卡片视图. 你可以直接使用标准引导HTML结构, 但ABP [标签助手](../../UI/AspNetCore/Tag-Helpers/Index.md) 使它更容易并且更安全.
此页面导入一个 CSS 和 JavaScript 文件, 所以我们需要创建它们.
### Index.js
打开 *TodoApp.Web* 项目中`Pages`文件夹下的`Index.js`, 并替换为以下内容:
````js
$(function () {
// DELETING ITEMS /////////////////////////////////////////
$('#TodoList').on('click', 'li i', function(){
var $li = $(this).parent();
var id = $li.attr('data-id');
todoApp.todo.delete(id).then(function(){
$li.remove();
abp.notify.info('Deleted the todo item.');
});
});
// CREATING NEW ITEMS /////////////////////////////////////
$('#NewItemForm').submit(function(e){
e.preventDefault();
var todoText = $('#NewItemText').val();
todoApp.todo.create(todoText).then(function(result){
$('<li data-id="' + result.id + '">')
.html('<i class="fa fa-trash-o"></i> ' + result.text)
.appendTo($('#TodoList'));
$('#NewItemText').val('');
});
});
});
````
在第一部分中, 我们注册了在待办事项旁边的删除图标的点击事件, 来删除服务器上的相关项目并在UI上显示通知. 此外, 我们会从 DOM 中移除已删除的项目, 所以我们不需要刷新页面.
在第二部分中, 我们在服务器上创建一个新的待办事项. 如果成功, 我们将操纵DOM来将新的 `<li>` 元素插入到待办事项列表. 这样我们不需要在创建新的待办事项后刷新整个页面.
这里有趣的部分是我们如何与服务器通信. 请参阅 *动态JavaScript代理和自动API控制器* 部分来了解其工作原理. 但是现在让我们继续并完成这个应用程序.
### Index.css
最后, 请打开 *TodoApp.Web* 项目的 `Pages` 文件夹中的 `Index.css` 文件, 并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式. 我们相信你可以做得更好 :)
现在, 你可以再次运行应用程序并看到结果.
### 动态JavaScript代理和自动API控制器
`Index.js` 文件中, 我们使用了 `todoApp.todo.delete(...)``todoApp.todo.create(...)` 方法来与服务器通信. 这些函数是由ABP框架动态创建的, 这要归功于 [动态JavaScript客户端代理](../../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) 系统. 它们执行 HTTP API 到服务器调用并返回一个Promise对象, 这样你就可以使用 `then` 函数注册一个回调, 像之前所做的那样.
但是, 你可能会注意到我们还没有创建任何API控制器, 所以服务器如何处理这些请求? 这个问题为我们引出了ABP 框架的 [自动API控制器](../../API/Auto-API-Controllers.md) 功能. 它通过约定自动将应用程序服务转换为 API 控制器.
如果你在应用程序URL中输入 `/swagger` 来打开 [Swagger UI](https://swagger.io/tools/swagger-ui/) , 就会看到Todo API:
![todo-api](todo-api.png)
{{else if UI=="Blazor" || UI=="BlazorServer"}}
### Index.razor.cs
打开在*TodoApp.Blazor*项目的`Pages`文件夹中`Index.razor.cs`文件, 并替换为一下内容:
````csharp
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Blazor.Pages
{
public partial class Index
{
[Inject]
private ITodoAppService TodoAppService { get; set; }
private List<TodoItemDto> TodoItems { get; set; } = new List<TodoItemDto>();
private string NewTodoText { get; set; }
protected async override Task OnInitializedAsync()
{
TodoItems = await TodoAppService.GetListAsync();
}
private async Task Create()
{
var result = await TodoAppService.CreateAsync(NewTodoText);
TodoItems.Add(result);
NewTodoText = null;
}
private async Task Delete(TodoItemDto todoItem)
{
await TodoAppService.DeleteAsync(todoItem.Id);
await Notify.Info("Deleted the todo item.");
TodoItems.Remove(todoItem);
}
}
}
````
此类使用 `ITodoAppService` 来执行待办事项的操作. 它在创建和删除操作后操纵 `TodoItems` 列表. 这样, 我们不需要从服务器刷新整个待办事项列表.
{{if UI=="Blazor"}}
请参阅下面的 *动态C#代理和自动API控制器* 部分, 来了解我们如何在浏览器上运行的 Blazor 应用程序中使用注入和应用服务接口的! 但是现在让我们继续并完成这个应用程序.
{{end # Blazor}}
### Index.razor
打开在 *TodoApp.Blazor* 项目的`Pages`文件夹中 `Index.razor`文件, 并替换为以下代码块内容:
````xml
@page "/"
@inherits TodoAppComponentBase
<div class="container">
<Card>
<CardHeader>
<CardTitle>
TODO LIST
</CardTitle>
</CardHeader>
<CardBody>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm"
@onsubmit:preventDefault
@onsubmit="() => Create()"
class="form-inline">
<input type="text"
@bind-value="@NewTodoText"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in TodoItems)
{
<li data-id="@todoItem.Id">
<i class="far fa-trash-alt"
@onclick="() => Delete(todoItem)"
></i> @todoItem.Text
</li>
}
</ul>
</CardBody>
</Card>
</div>
````
### Index.razor.css
最后, 请打开 *TodoApp.Blazor* 项目的 `Pages` 文件夹中的 `Index.razor.css`文件, 并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式. 我们相信你可以做得更好 :)
现在, 你可以再次运行应用程序来查看结果.
{{if UI=="Blazor"}}
### 动态C#代理和自动API控制器
`Index.razor.cs` 文件中, 我们已经注入(使用 `[Inject]` 特性)并像使用本地服务一样使用 `ITodoAppService`. 请记住, Blazor应用程序是在浏览器上运行, 但此应用程序服务的实现却是在服务器上运行的.
这个神奇的过程是由ABP框架的 [动态C#客户端代理](../../API/Dynamic-CSharp-API-Clients.md) 系统完成. 它使用标准的`HttpClient` 并执行HTTP API到远程服务器请求. 它还为我们处理所有标准任务, 包括授权、JSON序列化和异常处理.
但是, 你可能会问我们还没有创建任何API控制器, 那么服务器如何处理这些请求呢? 这个问题为我们引出了ABP 框架的 [自动API控制器](../../API/Auto-API-Controllers.md) 功能. 它通过约定自动将应用程序服务转换为 API 控制器.
如果你运行 `TodoApp.HttpApi.Host` 应用程序, 你可以看到Todo API:
![todo-api](todo-api.png)
{{end # Blazor}}
{{else if UI=="NG"}}
### 服务代理生成
ABP提供了一个便捷的功能来自动创建客户端服务, 以方便地使用由服务器提供的HTTP API.
你首先需要运行 `TodoApp.HttpApi.Host` 项目, 因为代理生成器从服务器应用程序读取API定义.
> **请注意**: IIS Express有一个问题: 它不允许从另一个进程连接到应用程序. 如果你使用的是Visual Studio, 请在 “运行” 按钮下拉列表中选择`TodoApp.HttpApi.Host` 来替代IIS Express, 如下图所示:
![运行时不使用 iisexpress](run-without-iisexpress.png)
当启动 `TodoApp.HttpApi.Host` 项目后, 在`angular`文件夹中打开一个命令行终端并输入以下命令:
````bash
abp generate-proxy
````
如果一切顺利, 它应该生成如下输出:
````bash
CREATE src/app/proxy/generate-proxy.json (170978 bytes)
CREATE src/app/proxy/README.md (1000 bytes)
CREATE src/app/proxy/todo.service.ts (794 bytes)
CREATE src/app/proxy/models.ts (66 bytes)
CREATE src/app/proxy/index.ts (58 bytes)
````
然后, 我们可以使用 `todoService` 来使用服务器端HTTP API, 就像我们将在下一节中做的那样.
### home.component.ts
打开 `/angular/src/app/home/home.component.ts` 文件, 并用以下代码块替换其内容:
````js
import { ToasterService } from '@abp/ng.theme.shared';
import { Component, OnInit } from '@angular/core';
import { TodoItemDto, TodoService } from '@proxy';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
todoItems: TodoItemDto[];
newTodoText: string;
constructor(
private todoService: TodoService,
private toasterService: ToasterService)
{ }
ngOnInit(): void {
this.todoService.getList().subscribe(response => {
this.todoItems = response;
});
}
create(): void{
this.todoService.create(this.newTodoText).subscribe((result) => {
this.todoItems = this.todoItems.concat(result);
this.newTodoText = null;
});
}
delete(id: string): void {
this.todoService.delete(id).subscribe(() => {
this.todoItems = this.todoItems.filter(item => item.id !== id);
this.toasterService.info('Deleted the todo item.');
});
}
}
````
我们已经实现了使用 `todoService` 来获取待办事项目列表, 并将返回值赋值给 `todoItems` 数组. 我们还添加了 `create``delete` 方法. 这些方法将在视图端使用.
### home.component.html
打开 `/angular/src/app/home/home.component.html` 文件, 并用以下代码块替换其内容:
````html
<div class="container">
<div class="card">
<div class="card-header">
<div class="card-title">TODO LIST</div>
</div>
<div class="card-body">
<!-- FORM FOR NEW TODO ITEMS -->
<form class="form-inline" (ngSubmit)="create()">
<input
name="NewTodoText"
type="text"
[(ngModel)]="newTodoText"
class="form-control mr-2"
placeholder="enter text..."
/>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
<li *ngFor="let todoItem of todoItems">
<i class="fa fa-trash-o" (click)="delete(todoItem.id)"></i> {%{{{ todoItem.text }}}%}
</li>
</ul>
</div>
</div>
</div>
````
### home.component.scss
最后, 打开`/angular/src/app/home/home.component.scss` 文件, 并用以下代码块替换其内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式. 我们相信你可以做得更好 :)
现在, 你可以再次运行应用程序来查看结果.
{{end}}
## 总结
在这个教程中, 我们已经建立了一个非常简单的应用程序来熟悉 ABP 框架. 如果你想要构建一个实际场景的应用程序, 请查看 [web 应用程序开发教程](../Part-1.md), 该教程涵盖了真实的 Web 应用程序开发的所有方面.
## 源代码
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)找到已完成的项目源代码.
## 另请参见
* [Web应用程序开发教程](../Part-1.md)

0
docs/zh-Hans/Tutorials/todo/run-without-iisexpress.png → docs/zh-Hans/Tutorials/Todo/run-without-iisexpress.png

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

0
docs/zh-Hans/Tutorials/todo/todo-api.png → docs/zh-Hans/Tutorials/Todo/todo-api.png

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/zh-Hans/Tutorials/Todo/todo-efcore-migration.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

0
docs/zh-Hans/Tutorials/todo/todo-list.png → docs/zh-Hans/Tutorials/Todo/todo-list.png

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
docs/zh-Hans/Tutorials/todo/todo-swagger-ui-initial.png → docs/zh-Hans/Tutorials/Todo/todo-swagger-ui-initial.png

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

0
docs/zh-Hans/Tutorials/todo/todo-ui-initial.png → docs/zh-Hans/Tutorials/Todo/todo-ui-initial.png

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

822
docs/zh-Hans/Tutorials/todo/Index.md

@ -1,822 +0,0 @@
# 快速入门
````json
//[doc-params]
{
"UI": ["MVC", "Blazor", "BlazorServer", "NG"],
"DB": ["EF", "Mongo"]
}
````
这是一个单独的部分,使用ABP框架构建简单待办事项应用程序的快速入门教程.这是一个最终应用的截图:
![todo-list](todo-list.png)
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)找到已完成的项目源代码.
## 先决条件
* 一个集成开发环境 (比如: [Visual Studio](https://visualstudio.microsoft.com/vs/)) 它需要支持 [.NET 5.0+](https://dotnet.microsoft.com/download/dotnet) 的开发.
{{if DB=="Mongo"}}
* [MongoDB Server 4.0+](https://docs.mongodb.com/manual/administration/install-community/)
{{end}}
{{if UI=="NG"}}
* [Node v14.x](https://nodejs.org/)
{{end}}
## 创建新的解决方案
我们将使用[ABP CLI](../../CLI.md) 创建带有ABP框架的新解决方案. 你可以在命令行终端中运行以下命令来安装它:
````bash
dotnet tool install -g Volo.Abp.Cli
````
然后创建一个空文件夹,打开命令行终端并以打开的文件夹为路径在终端中执行以下命令:
````bash
abp new TodoApp{{if UI=="Blazor"}} -u blazor{{else if UI=="BlazorServer"}} -u blazor-server{{else if UI=="NG"}} -u angular{{end}}{{if DB=="Mongo"}} -d mongodb{{end}}
````
{{if UI=="NG"}}
这将创建一个名为*TodoApp*的新解决方案,其中包含`angular`和`aspnet core`文件夹.解决方案就绪后,在你的IDE中打开ASP.NET Core 解决方案.
{{else}}
这将创建一个名为*TodoApp*的新解决方案.解决方案准备好后,在你的IDE中打开它.
{{end}}
### 创建数据库
如果你使用的是visual studio,请右键单击`TodoApp.DbMigrator`项目,选择*设置为启动项目*,然后按*Ctrl+F5*运行它而不进行调试.它将创建初始数据库并播种初始数据.
{{if DB=="EF"}}
> 由于*DbMigrator*添加初始迁移并重新编译项目,一些ide(例如Rider)在第一次运行时可能会出现问题.在这种情况下,请打开`.DbMigrator`项目文件夹中的命令行终端,然后执行`dotnet run`命令.
{{end}}
### 运行应用程序
{{if UI=="MVC" || UI=="BlazorServer"}}
最好在开始开发之前运行一下应用程序.确保 {{if UI=="BlazorServer"}}`TodoApp.Blazor`{{else}}`TodoApp.Web`{{end}} 是启动项目,然后运行应用程序(Visual Studio中是Ctrl+F5)以查看查看初始UI:
{{else if UI=="Blazor"}}
最好在开始开发之前运行一下应用程序.该解决方案有两个主要应用:
* `TodoApp.HttpApi.Host` 托管服务器端的 HTTP API.
* `TodoApp.Blazor` 客户端托管的 Blazor WebAssembly 应用.
确保 `TodoApp.HttpApi.Host` 是启动项目,然后运行应用程序(Visual Studio中的Ctrl+F5)以查看[Swagger UI](https://swagger.io/tools/swagger-ui/)上server-side 的 HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用此UI查看和测试你的HTTP API.现在,我们可以将 `TodoApp.Blazor` 设置为启动项目,并运行它来打开实际的Blazor应用程序UI:
{{else if UI=="NG"}}
最好在开始开发之前运行应用程序.该解决方案有两个主要应用:
* `TodoApp.HttpApi.Host` (在.NET解决方案中)承载服务器端HTTP API.
* `angular` 文件夹包含 Angular 应用程序.
确保`TodoApp.HttpApi.Host`project是启动项目,然后运行应用程序(visual studio中是Ctrl+F5)以查看[Swagger UI](https://swagger.io/tools/swagger-ui/)上server-side HTTP API:
![todo-swagger-ui-initial](todo-swagger-ui-initial.png)
你可以使用这个UI查看和测试你的HTTP API.如果可以的话,我们可以运行Angular客户端应用程序.
首先,运行以下命令来还原NPM包:
````bash
npm install
````
安装所有软件包需要一些时间.然后可以使用以下命令运行应用程序:
````bash
npm start
````
此命令需要一点时间,但最终会在默认浏览器中运行并打开应用程序:
{{end}}
![todo-ui-initial](todo-ui-initial.png)
你可以单击 *登录* 按钮,以`admin`作为用户名,`1q2w3E*` 作为密码登录到应用程序.
一切就绪.我们可以开始编码了!
## 领域层
此应用程序只有一个 [实体](../../Entities.md) 我们开始创建它. 在*TodoApp.Domain*项目中创建一个新的 `TodoItem` 类:
````csharp
using System;
using Volo.Abp.Domain.Entities;
namespace TodoApp
{
public class TodoItem : BasicAggregateRoot<Guid>
{
public string Text { get; set; }
}
}
````
`BasicAggregateRoot` 是创建根实体的最简单的基类之一,`Guid` 是这里实体的主键 (`Id`).
## Database Integration 数据库集成
{{if DB=="EF"}}
下一步是配置 [Entity Framework Core](../../Entity-Framework-Core.md).
### Mapping Configuration 映射配置
*TodoApp.EntityFrameworkCore* 项目的 `EntityFrameworkCore` 文件夹中打开 `TodoAppDbContext` 类,并向该类添加一个新的 `DbSet` 属性:
````csharp
public DbSet<TodoItem> TodoItems { get; set; }
````
然后在同一文件夹中打开 `TodoAppDbContextModelCreatingExtensions` 类,并为 `TodoItem` 类添加映射配置,如下所示:
````csharp
public static void ConfigureTodoApp(this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
builder.Entity<TodoItem>(b =>
{
b.ToTable("TodoItems");
});
}
````
我们已经将 `TodoItem` 实体映射到数据库中的 `TodoItems` 表.
### 代码优先迁移
解决方案启动模版已经配置为使用Entity Framework Core [Code First 迁移](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations).由于我们已经更改了数据库映射配置,因此我们应该创建一个新的迁移并将更改应用于数据库.
*TodoApp.EntityFrameworkCore.DbMigrations* 项目的目录中打开一个命令行终端,然后键入以下命令:
````bash
dotnet ef migrations add Added_TodoItem
````
这将向项目添加一个新的迁移类:
![todo-efcore-migration](todo-efcore-migration.png)
你可以在同一命令行终端中使用以下命令将更改应用于数据库:
````bash
dotnet ef database update
````
> 如果你使用的是Visual Studio,*则可能希望在包管理器控制台 (PMC)* 中使用 `Add-Migration Added_TodoItem``Update-Database` 命令.在这种情况下,请确保 {{if UI=="MVC"}}`TodoApp.Web`{{else if UI=="BlazorServer"}}`TodoApp.Blazor`{{else if UI=="Blazor" || UI=="NG"}}`TodoApp.HttpApi.Host`{{end}} 是启动项目,并且 `TodoApp.EntityFrameworkCore.DbMigrations` 是PMC中的 *默认项目*.
{{else if DB=="Mongo"}}
下一步是设置 [MongoDB](../MongoDB.md) 配置.在 *TodoApp.MongoDB* 项目的 `MongoDb` 文件夹中打开 `TodoAppMongoDbContext` 类,并进行以下更改;
1. 向类添加新属性:
````csharp
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>();
````
2. 在 `CreateModel` 方法中添加以下代码:
````csharp
modelBuilder.Entity<TodoItem>(b =>
{
b.CollectionName = "TodoItems";
});
````
{{end}}
现在,我们可以使用ABP仓储来保存和检索待办事项列表项了,就像我们将在下一节中做的那样.
## 应用层
[应用服务](../../Application-Services.md) 用于执行应用程序的用例.我们需要执行以下用例;
* 获取待办事项列表
* 创建新的待办事项
* 删除现有的待办事项
### 应用服务接口
我们可以从为应用程序服务定义一个接口开始.在 *TodoApp.Application.Contracts* 项目中创建一个新的 `ITodoAppService` 接口,如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace TodoApp
{
public interface ITodoAppService : IApplicationService
{
Task<List<TodoItemDto>> GetListAsync();
Task<TodoItemDto> CreateAsync(string text);
Task DeleteAsync(Guid id);
}
}
````
### 数据传输对象
`GetListAsync``CreateAsync` 方法返回 `TodoItemDto`. 通常应用服务获取或返回的是 DTO ([数据传输对象](../../Data-Transfer-Objects.md)) 而不是直接获取或返回实体对象. 所以,我们应该在此定义 DTO(数据传输对象) 类. 在 *TodoApp.Application.Contracts* 项目中创建一个名为 `TodoItemDto` 的类:
````csharp
using System;
namespace TodoApp
{
public class TodoItemDto
{
public Guid Id { get; set; }
public string Text { get; set; }
}
}
````
这是一个非常简单的DTO类,与我们的 `TodoItem` 实体相对应.我们接下来实现 `ITodoAppService` 接口.
### 应用服务实现
*TodoApp.Application* 项目内部创建一个 `TodoAppService` 类,如下所示:
````csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace TodoApp
{
public class TodoAppService : ApplicationService, ITodoAppService
{
private readonly IRepository<TodoItem, Guid> _todoItemRepository;
public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository)
{
_todoItemRepository = todoItemRepository;
}
// TODO: Implement the methods here...
}
}
````
该类继承自ABP框架的 `ApplicationService` 类,并实现了之前定义的 `ITodoAppService`接口.ABP为实体提供默认的通用的 [仓储](../repositories.md).我们可以使用它们来执行基本的数据库操作. 这个类 [注入](../Dependency-Injection.md) `IRepository<TodoItem, Guid>` 它是 `TodoItem` 实体的默认存储库.我们将使用它来实现之前描述的用例.
#### 获取所有待办事项列表
让我们开始实现 `GetListAsync` 方法:
````csharp
public async Task<List<TodoItemDto>> GetListAsync()
{
var items = await _todoItemRepository.GetListAsync();
return items
.Select(item => new TodoItemDto
{
Id = item.Id,
Text = item.Text
}).ToList();
}
````
我们只是简单的从数据库中获取完整的 `TodoItem` 列表,将它们映射到 `TodoItemDto` 对象并作为结果返回.
#### 创建一个新的待办事项
下一个方法是 `CreateAsync`,我们可以像如下所示来实现:
````csharp
public async Task<TodoItemDto> CreateAsync(string text)
{
var todoItem = await _todoItemRepository.InsertAsync(
new TodoItem {Text = text}
);
return new TodoItemDto
{
Id = todoItem.Id,
Text = todoItem.Text
};
}
````
仓储的 `InsertAsync` 方法将给定的 `TodoItem` 插入数据库,并返回相同的 `TodoItem` 对象.它还设置了 `Id`,因此我们可以在返回对象上使用它.我们只是通过从新的 `TodoItem` 实体创建和返回 `TodoItemDto`.
#### 删除待办事项
最后,我们可以将 `DeleteAsync` 实现为以下代码块:
````csharp
public async Task DeleteAsync(Guid id)
{
await _todoItemRepository.DeleteAsync(id);
}
````
至此,应用程序服务已准备好了让UI层来使用.
## 用户界面层
是时候在UI上显示待办事项了!在开始编写代码之前,最好记住我们正在尝试构建的内容.这是最终UI的示例屏幕截图:
![todo-list](todo-list.png)
> **我们将在本教程中保持最简洁轻量的UI端,以使本教程简单且重点突出.请参阅[web应用程序开发教程](../Part-1.md) 以构建包含各个方面的真实页面.**
{{if UI=="MVC"}}
### Index.cshtml.cs
*TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.cshtml.cs` 文件,并用以下代码块替换它的默认内容:
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Web.Pages
{
public class IndexModel : TodoAppPageModel
{
public List<TodoItemDto> TodoItems { get; set; }
private readonly ITodoAppService _todoAppService;
public IndexModel(ITodoAppService todoAppService)
{
_todoAppService = todoAppService;
}
public async Task OnGetAsync()
{
TodoItems = await _todoAppService.GetListAsync();
}
}
}
````
此类使用 `ITodoAppService` 获取待办事项目列表并将它赋值给 `TodoItems` 属性.我们将用它来渲染razor页面上的待办事项目列表.
### Index.cshtml
*TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.cshtml` 文件,并替换为以下内容:
````xml
@page
@model TodoApp.Web.Pages.IndexModel
@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>
TODO LIST
</abp-card-title>
</abp-card-header>
<abp-card-body>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm" class="form-inline">
<input id="NewItemText"
type="text"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in Model.TodoItems)
{
<li data-id="@todoItem.Id">
<i class="fa fa-trash-o"></i> @todoItem.Text
</li>
}
</ul>
</abp-card-body>
</abp-card>
</div>
````
我们使用ABP的 [卡片标签助手](../../UI/AspNetCore/Tag-Helpers/Cards.md) 创建一个简单的卡片视图.你可以直接使用标准的bootstrap HTML, 不过ABP的[标签助手](../../UI/AspNetCore/Tag-Helpers/Index.md) 使它更简单并且类型安全.
这个页面要导入一个CSS和一个JavaScript文件,所以我们也应该创建它们.
### Index.js
*TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.js` 文件,并替换为以下内容:
````js
$(function () {
// DELETING ITEMS /////////////////////////////////////////
$('#TodoList').on('click', 'li i', function(){
var $li = $(this).parent();
var id = $li.attr('data-id');
todoApp.todo.delete(id).then(function(){
$li.remove();
abp.notify.info('Deleted the todo item.');
});
});
// CREATING NEW ITEMS /////////////////////////////////////
$('#NewItemForm').submit(function(e){
e.preventDefault();
var todoText = $('#NewItemText').val();
todoApp.todo.create(todoText).then(function(result){
$('<li data-id="' + result.id + '">')
.html('<i class="fa fa-trash-o"></i> ' + result.text)
.appendTo($('#TodoList'));
$('#NewItemText').val('');
});
});
});
````
在第一部分中,我们在待办事项目附近注册点击删除图标所要触发的事件,删除服务器上的相关待办事项并在UI上显示通知.另外,我们从DOM中删除已删除的项,因此我们不需要刷新页面.
在第二部分中,我们在服务器上创建一个新的待办事项.如果成功,我们将操纵DOM以将新的 `<li>` 元素插入todo列表.这样,创建新的待办事项后就不用刷新整个页面了.
这里有趣的部分是我们如何与服务器通信.请参阅 *动态JavaScript代理和自动API控制器* 部分,以了解其工作原理.但是现在让我们继续并完成这个应用程序.
### Index.css
来到最后要做的工作,请打开 *TodoApp.Web* 项目的 `Pages` 文件夹中的 `Index.css` 文件,并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式.我们相信你可以做得更好 :)
现在,你可以再次运行应用程序以查看结果.
### Dynamic JavaScript Proxies & Auto API Controllers 动态JavaScript代理和自动应用编程接口控制器
`Index.js` 文件中,我们使用了 `todoApp.todo.delete(...)``todoApp.todo.create(...)` 函数与服务器通信.这些函数是由ABP框架动态创建的,这要归功于 [动态JavaScript客户端代理](../UI/AspNetCore/Dynamic-JavaScript-Proxies.md) 系统.他们对服务器执行HTTP API调用并返回承诺,因此你可以像上面所做的那样注册对 `then` 函数的回调.
但是,你可能会问我们还没有创建任何API控制器,那么服务器如何处理这些请求呢? 这个问题为我们引出了ABP框架的 [自动API控制器](../API/Auto-API-Controllers.md) 功能.它通过约定自动将应用程序服务转换为API Controllers(API控制器).
如果通过在应用程序中输入 `/swagger` URL来打开 [swagger UI](https://swagger.io/tools/ Swagger-ui/),则可以看到Todo API:
![todo-api](todo-api.png)
{{else if UI=="Blazor" || UI=="BlazorServer"}}
### Index.razor.cs
*TodoApp.Blazor* 项目的 `Pages` 文件夹中打开 `Index.razor.cs` 文件,并用以下代码块替换内容:
````csharp
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TodoApp.Blazor.Pages
{
public partial class Index
{
[Inject]
private ITodoAppService TodoAppService { get; set; }
private List<TodoItemDto> TodoItems { get; set; } = new List<TodoItemDto>();
private string NewTodoText { get; set; }
protected async override Task OnInitializedAsync()
{
TodoItems = await TodoAppService.GetListAsync();
}
private async Task Create()
{
var result = await TodoAppService.CreateAsync(NewTodoText);
TodoItems.Add(result);
NewTodoText = null;
}
private async Task Delete(TodoItemDto todoItem)
{
await TodoAppService.DeleteAsync(todoItem.Id);
await Notify.Info("Deleted the todo item.");
TodoItems.Remove(todoItem);
}
}
}
````
这个类使用 `ITodoAppService` 对待办事项执行操作.它在创建和删除操作后操纵 `TodoItems` 列表.这样,我们不需要从服务器刷新整个todo列表.
{{if UI=="Blazor"}}
请参阅下面的 *动态C # 代理和自动API控制器* 部分,了解如何从浏览器上运行的Blazor应用程序注入和使用应用程序服务接口!但是现在,让我们继续并完成这个应用.
{{end # Blazor}}
### Index.razor
*TodoApp.Blazor* 项目的 `Pages` 文件夹中打开 `Index.razor` 文件,并用以下代码块替换内容:
````xml
@page "/"
@inherits TodoAppComponentBase
<div class="container">
<Card>
<CardHeader>
<CardTitle>
TODO LIST
</CardTitle>
</CardHeader>
<CardBody>
<!-- FORM FOR NEW TODO ITEMS -->
<form id="NewItemForm"
@onsubmit:preventDefault
@onsubmit="() => Create()"
class="form-inline">
<input type="text"
@bind-value="@NewTodoText"
class="form-control mr-2"
placeholder="enter text...">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
@foreach (var todoItem in TodoItems)
{
<li data-id="@todoItem.Id">
<i class="far fa-trash-alt"
@onclick="() => Delete(todoItem)"
></i> @todoItem.Text
</li>
}
</ul>
</CardBody>
</Card>
</div>
````
### Index.razor.css
最后,请在 *TodoApp.Web* 项目的 `Pages` 文件夹中打开 `Index.razor.css` 文件,并替换为以下内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式.我们相信你可以做得更好 :)
现在,你可以再次运行应用程序以查看结果.
{{if UI=="Blazor"}}
### Dynamic C# Proxies & Auto API Controllers 动态C#代理和自动应用编程接口控制器
`Index.razor.cs` 文件中,我们已经注入(使用 `[Inject]` 特性)并像使用本地服务一样使用 `ITodoAppService`.请记住,当此应用程序服务的实例在服务器上运行的同时,Blazor应用程序正在浏览器上运行.
这个神奇的过程是由ABP框架的 [动态C#客户端代理](../API/Dynamic-CSharp-API-Clients.md) 系统完成的.它使用标准的 `HttpClient` 并向远程服务器执行HTTP API请求.它还为我们处理所有标准任务,包括授权,JSON序列化和异常处理.
但是,你可能会问我们还没有创建任何API控制器,那么服务器如何处理这些请求呢? 这个问题为我们引出了ABP框架的 [自动API控制器](../API/Auto-API-Controllers.md) 功能.它通过约定自动将应用程序服务转换为API控制器.
如果你运行 `TodoApp.HttpApi.Host` 应用程序,你可以看到Todo API:
![todo-api](todo-api.png)
{{end # Blazor}}
{{else if UI=="NG"}}
### 服务代理生成
ABP提供了一个方便的功能,可以自动创建客户端服务,轻松使用服务器提供的HTTP APIs.
你首先需要运行 `TodoApp.HttpApi.Host` 项目,因为代理生成器从服务器应用程序读取API定义.
> **请注意**: IIS Express有问题; 它不允许从另一个进程连接到应用程序.如果你使用的是Visual Studio,请在 “运行” 按钮下拉列表中选择 `TodoApp.HttpApi.Host` 而不是IIS Express,如下图所示:
![run-without-iisexpress](run-without-iisexpress.png)
运行 `TodoApp.HttpApi.Host` 项目后,在 `angular` 文件夹中打开命令行终端,然后键入以下命令:
````bash
abp generate-proxy
````
如果一切顺利,应该生成如下所示的输出:
````bash
CREATE src/app/proxy/generate-proxy.json (170978 bytes)
CREATE src/app/proxy/README.md (1000 bytes)
CREATE src/app/proxy/todo.service.ts (794 bytes)
CREATE src/app/proxy/models.ts (66 bytes)
CREATE src/app/proxy/index.ts (58 bytes)
````
然后,我们可以使用 `todoService` 来使用服务器端HTTP APIs,就像我们将在下一节中做的那样.
### home.component.ts
打开 `/angular/src/app/home/home.component.ts` 文件,并用以下代码块替换其内容:
````js
import { ToasterService } from '@abp/ng.theme.shared';
import { Component, OnInit } from '@angular/core';
import { TodoItemDto, TodoService } from '@proxy';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
todoItems: TodoItemDto[];
newTodoText: string;
constructor(
private todoService: TodoService,
private toasterService: ToasterService)
{ }
ngOnInit(): void {
this.todoService.getList().subscribe(response => {
this.todoItems = response;
});
}
create(): void{
this.todoService.create(this.newTodoText).subscribe((result) => {
this.todoItems = this.todoItems.concat(result);
this.newTodoText = null;
});
}
delete(id: string): void {
this.todoService.delete(id).subscribe(() => {
this.todoItems = this.todoItems.filter(item => item.id !== id);
this.toasterService.info('Deleted the todo item.');
});
}
}
````
我们已经实现了使用 `todoService` 来获取待办事项目列表,并将返回值赋值给 `todoItems` 数组.我们还添加了 `create``delete` 方法.这些方法将在视图端使用.
### home.component.html
打开 `/angular/src/app/home/home.component.html` 文件,并用以下代码块替换其内容:
````html
<div class="container">
<div class="card">
<div class="card-header">
<div class="card-title">TODO LIST</div>
</div>
<div class="card-body">
<!-- FORM FOR NEW TODO ITEMS -->
<form class="form-inline" (ngSubmit)="create()">
<input
name="NewTodoText"
type="text"
[(ngModel)]="newTodoText"
class="form-control mr-2"
placeholder="enter text..."
/>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<!-- TODO ITEMS LIST -->
<ul id="TodoList">
<li *ngFor="let todoItem of todoItems">
<i class="fa fa-trash-o" (click)="delete(todoItem.id)"></i> {%{{{ todoItem.text }}}%}
</li>
</ul>
</div>
</div>
</div>
````
### home.component.scss
最后的最后,打开 `/angular/src/app/home/home.component.scss` 文件,并用以下代码块替换其内容:
````css
#TodoList{
list-style: none;
margin: 0;
padding: 0;
}
#TodoList li {
padding: 5px;
margin: 5px 0px;
border: 1px solid #cccccc;
background-color: #f5f5f5;
}
#TodoList li i
{
opacity: 0.5;
}
#TodoList li i:hover
{
opacity: 1;
color: #ff0000;
cursor: pointer;
}
````
这是待办事项页面的简单样式.我们相信你可以做得更好 :)
现在,你可以再次运行应用程序以查看结果.
{{end}}
## 总结
在本教程中,我们构建了一个非常简单的应用程序来抢先探究ABP框架的新特性.如果你想构建一个实际场景的应用程序,请查看 [应用程序开发教程](../Part-1.md),其中涵盖了实际web应用程序开发的所有方面.
## 源代码
你可以在[这里](https://github.com/abpframework/abp-samples/tree/master/TodoApp)获取到完整的应用程序源代码.
## 另请参见
* [Web应用程序开发教程](../Part-1.md)

BIN
docs/zh-Hans/Tutorials/todo/todo-efcore-migration.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

16
docs/zh-Hans/UI/AspNetCore/Client-Side-Package-Management.md

@ -18,7 +18,7 @@ ABP是一个模块化平台. 每个开发人员都可以创建模块, 模块应
**标准包**的好处是:
* 它取决于包装的**标准版本**. 取决于此包是**安全**,因为所有模块都依赖于相同的版本.
* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹的gulp任务. 有关更多信息, 请参阅 *映射库资源* 部分.
* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹. 有关更多信息, 请参阅 *映射库资源* 部分.
依赖标准包装很容易. 只需像往常一样将它添加到**package.json**文件中. 例如:
@ -61,7 +61,7 @@ yarn
下一个挑战是将所需的资源(js,css,img ...文件)从`node_modules`复制到**wwwroot**文件夹内的文件夹中,以使其可供客户端/浏览器访问.
ABP将基于[Gulp](https://gulpjs.com/)的任务定义为**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项.
ABP`install-libs` 命令**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项.
**启动模板**已经配置为开箱即用的所有这些. 本节将介绍配置选项.
@ -97,17 +97,15 @@ mappings: {
}
````
#### 使用 Gulp
#### install-libs 命令
正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行gulp命令:
正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行ABP CLI命令:
````bash
abp install-libs
````
gulp
````
当你运行`gulp`时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`yarn&gulp`.
> 运行Gulp命令时, 使用package.json文件解析应用程序的依赖关系. Gulp任务自动发现并映射来自所有依赖项的所有资源(递归).
当你运行这个命令时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`abp install-libs`.
#### 参见

7
docs/zh-Hans/Validation.md

@ -130,8 +130,8 @@ namespace Acme.BookStore
除了自动验证你可能需要手动验证对象,这种情况下[注入](Dependency-Injection.md)并使用 `IObjectValidator` 服务:
* `Validate` 方法根据验证​​规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常.
* `GetErrors` 不会抛出异常,只返回验证错误.
* `ValidateAsync` 方法根据验证​​规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常.
* `GetErrorsAsync` 不会抛出异常,只返回验证错误.
`IObjectValidator` 默认由 `ObjectValidator` 实现. `ObjectValidator`是可扩展的; 可以实现`IObjectValidationContributor`接口提供自定义逻辑.
示例 :
@ -140,13 +140,14 @@ namespace Acme.BookStore
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
public void AddErrors(ObjectValidationContext context)
public Task AddErrorsAsync(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
return Task.CompletedTask;
}
}
````

4
docs/zh-Hans/docs-nav.json

@ -1,5 +1,9 @@
{
"items": [
{
"text": "快速入门",
"path": "Tutorials/Todo/Index.md"
},
{
"text": "入门",
"items": [

2
docs/zh-Hans/docs-params.json

@ -5,6 +5,8 @@
"displayName": "UI",
"values": {
"MVC": "MVC / Razor Pages",
"Blazor": "Blazor WebAssembly",
"BlazorServer": "Blazor Server",
"NG": "Angular"
}
},

7
framework/Volo.Abp.sln

@ -387,6 +387,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.IdentityModel.Test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Threading.Tests", "test\Volo.Abp.Threading.Tests\Volo.Abp.Threading.Tests.csproj", "{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Auditing.Contracts", "src\Volo.Abp.Auditing.Contracts\Volo.Abp.Auditing.Contracts.csproj", "{508B6355-AD28-4E60-8549-266D21DBF2CF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1153,6 +1155,10 @@ Global
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B}.Release|Any CPU.Build.0 = Release|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{508B6355-AD28-4E60-8549-266D21DBF2CF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1348,6 +1354,7 @@ Global
{90B1866A-EF99-40B9-970E-B898E5AA523F} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{40C6740E-BFCA-4D37-8344-3D84E2044BB2} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{7B2FCAD6-86E6-49C8-ADBE-A61B4F4B101B} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{508B6355-AD28-4E60-8549-266D21DBF2CF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

0
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/JwtTokenMiddleware.cs → framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Microsoft/AspNetCore/Builder/ApplicationBuilderAbpJwtTokenMiddlewareExtension.cs

2
framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer/Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Authentication.JwtBearer</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Authentication.JwtBearer</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

27
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Properties/launchSettings.json

@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53601/",
"sslPort": 44330
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.AspNetCore.Authentication.OAuth": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

3
framework/src/Volo.Abp.AspNetCore.Authentication.OAuth/Volo.Abp.AspNetCore.Authentication.OAuth.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Authentication.OAuth</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Authentication.OAuth</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
@ -13,6 +13,7 @@
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<IsPackable>true</IsPackable>
<OutputType>Library</OutputType>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
<RootNamespace />
</PropertyGroup>

2
framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect/Volo.Abp.AspNetCore.Authentication.OpenIdConnect.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>

3
framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Volo.Abp.AspNetCore.Components.Server.Theming.csproj

@ -4,9 +4,10 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>true</IsPackable>
<OutputType>Library</OutputType>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
</PropertyGroup>
<ItemGroup>

3
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj

@ -4,9 +4,10 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>true</IsPackable>
<OutputType>Library</OutputType>
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
<RootNamespace />
</PropertyGroup>

11
framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs

@ -25,18 +25,19 @@ namespace Volo.Abp.AspNetCore.Components.Server
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddServerSideBlazor();
var serverSideBlazorBuilder = context.Services.AddServerSideBlazor();
context.Services.ExecutePreConfiguredActions(serverSideBlazorBuilder);
Configure<AbpAspNetCoreUnitOfWorkOptions>(options =>
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
Configure<AbpAspNetCoreAuditingOptions>(options =>
{
options.IgnoredUrls.AddIfNotContains("/_blazor");
});
Configure<AbpEndpointRouterOptions>(options =>
{
options.EndpointConfigureActions.Add(endpointContext =>
@ -56,4 +57,4 @@ namespace Volo.Abp.AspNetCore.Components.Server
);
}
}
}
}

0
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpBlazorRouterOptions.cs → framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Routing/AbpRouterOptions.cs

2
framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Volo.Abp.AspNetCore.Components.Web.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.Web/Volo.Abp.AspNetCore.Components.Web.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace />
</PropertyGroup>

0
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsWebAssemblyBundleContributor.cs → framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/ComponentsComponentsBundleContributor.cs

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>

2
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo.Abp.AspNetCore.Components.WebAssembly.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Components.WebAssembly</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Components.WebAssembly</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

2
framework/src/Volo.Abp.AspNetCore.Components/Volo.Abp.AspNetCore.Components.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.Components</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.Components</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

2
framework/src/Volo.Abp.AspNetCore.MultiTenancy/Volo.Abp.AspNetCore.MultiTenancy.csproj

@ -4,7 +4,7 @@
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Volo.Abp.AspNetCore.MultiTenancy</AssemblyName>
<PackageId>Volo.Abp.AspNetCore.MultiTenancy</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>

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

Loading…
Cancel
Save