@ -0,0 +1,125 @@ |
|||
# Blazor UI: Layout Hooks |
|||
|
|||
ABP Framework theming system places the page layout into the [theme](Theming.md) NuGet packages. That means the final application doesn't include a layout, so you can't directly change the layout code to customize it. |
|||
|
|||
> If you create a Blazor WASM project, the `index.html` file will be included within the template. You can also customize it to your needs. |
|||
|
|||
You can copy the theme code into your solution. In this case, you are completely free to customize it. However, then you won't be able to get automatic updates of the theme (by upgrading the theme NuGet package). |
|||
|
|||
The **Layout Hook System** allows you to **add code** at some specific parts of the layout. All layouts of all themes should implement these hooks. Finally, you can add a **razor component** into a hook point. |
|||
|
|||
## Example: Add a Simple Announcement Alert |
|||
|
|||
Assume that you need to add a simple banner to the layout (that will be available for all the pages) to make an announcement about your new product. First, **create a razor component** in your project: |
|||
|
|||
 |
|||
|
|||
**AnnouncementComponent.razor.cs** |
|||
|
|||
```csharp |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Components; |
|||
using Microsoft.JSInterop; |
|||
|
|||
namespace Acme.BookStore.Blazor.Components; |
|||
|
|||
public partial class AnnouncementComponent : ComponentBase |
|||
{ |
|||
private const string AnnouncementLocalStorageKey = "product-announcement-status"; |
|||
|
|||
[Inject] |
|||
public IJSRuntime JsRuntime { get; set; } |
|||
|
|||
public bool ShowBanner { get; set; } |
|||
|
|||
protected override async Task OnInitializedAsync() |
|||
{ |
|||
ShowBanner = await ShowAnnouncementBannerAsync(); |
|||
} |
|||
|
|||
private async Task<bool> ShowAnnouncementBannerAsync() |
|||
{ |
|||
var announcementLocalStorageValue = await JsRuntime.InvokeAsync<string>("localStorage.getItem", AnnouncementLocalStorageKey); |
|||
|
|||
return announcementLocalStorageValue != null && |
|||
bool.TryParse(announcementLocalStorageValue, out var showAnnouncementBanner) && showAnnouncementBanner; |
|||
} |
|||
|
|||
private async Task HideAnnouncementBannerAsync() |
|||
{ |
|||
await JsRuntime.InvokeVoidAsync("localStorage.setItem", AnnouncementLocalStorageKey, true); |
|||
ShowBanner = false; |
|||
StateHasChanged(); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
**AnnouncementComponent.razor** |
|||
|
|||
```html |
|||
@if(ShowBanner) |
|||
{ |
|||
<div class="alert alert-info"> |
|||
A brand new product is in sale. Click <a href="#">here</a> to learn more. |
|||
<button @onclick="async () => { await HideAnnouncementBannerAsync(); }">Hide</button> |
|||
</div> |
|||
} |
|||
``` |
|||
|
|||
Then, you can add this component to any of the hook points in the `ConfigureServices` of your module class: |
|||
|
|||
```csharp |
|||
Configure<AbpLayoutHookOptions>(options => |
|||
{ |
|||
options.Add( |
|||
LayoutHooks.Body.Last, //The hook name |
|||
typeof(AnnouncementComponent) //The component to add |
|||
); |
|||
}); |
|||
``` |
|||
|
|||
Now, the `AnnouncementComponent` will be rendered in the `body` of the page as the last item. |
|||
|
|||
### Specifying the Layout |
|||
|
|||
The configuration above adds the `AnnouncementComponent` to all layouts. You may want to only add it to a specific layout: |
|||
|
|||
````csharp |
|||
Configure<AbpLayoutHookOptions>(options => |
|||
{ |
|||
options.Add( |
|||
LayoutHooks.Body.Last, |
|||
typeof(AnnouncementComponent), |
|||
layout: StandardLayouts.Application //Set the layout to add |
|||
); |
|||
}); |
|||
```` |
|||
|
|||
See the *Layouts* section below to learn more about the layout system. |
|||
|
|||
## Layout Hook Points |
|||
|
|||
There are some pre-defined layout hook points. The standard hook points are: |
|||
|
|||
* `LayoutHooks.Body.First`: Used to add a component as the first item in the HTML body tag. |
|||
* `LayoutHooks.Body.Last`: Used to add a component as the last item in the HTML body tag. |
|||
|
|||
> You (or the modules you are using) can add **multiple items to the same hook point**. All of them will be added to the layout in the order they were added. |
|||
|
|||
## Layouts |
|||
|
|||
The layout system allows themes to define the standard named layouts and allows any page to select a proper layout for its purpose. There is one pre-defined layout: |
|||
|
|||
* "**Application**": The main (and the default) layout for an application. It typically contains a header, menu (sidebar), footer, toolbar... etc. |
|||
|
|||
This layout is defined in the `StandardLayouts` class as constants. You can definitely create your own layouts, but this layout is the standard layout and it's implemented by all the themes out of the box. |
|||
|
|||
> If you don't specify the layout, your razor component will be rendered in all of the layouts. |
|||
|
|||
### Layout Location |
|||
|
|||
You can find the `MainLayout.razor` [here](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/MainLayout.razor) for the basic theme. You can take it as a reference to build your own layouts or you can override it, if necessary. |
|||
|
|||
## See Also |
|||
|
|||
* [Customization / Overriding Components](Customization-Overriding-Components.md) |
|||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 65 KiB |
@ -0,0 +1,7 @@ |
|||
@if (LayoutHookViewModel.Hooks.Any()) |
|||
{ |
|||
foreach (var hook in LayoutHookViewModel.Hooks) |
|||
{ |
|||
<DynamicComponent Type="@hook.ComponentType" /> |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Components; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Ui.LayoutHooks; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Components.LayoutHooks; |
|||
|
|||
public partial class LayoutHook : ComponentBase |
|||
{ |
|||
[Parameter] |
|||
public string Name { get; set; } |
|||
|
|||
[Parameter] |
|||
public string Layout { get; set; } |
|||
|
|||
[Inject] |
|||
protected IOptions<AbpLayoutHookOptions> LayoutHookOptions { get; set; } |
|||
|
|||
protected LayoutHookViewModel LayoutHookViewModel { get; private set; } |
|||
|
|||
protected override Task OnInitializedAsync() |
|||
{ |
|||
if (LayoutHookOptions.Value.Hooks.TryGetValue(Name, out var layoutHooks)) |
|||
{ |
|||
layoutHooks = layoutHooks |
|||
.WhereIf(string.IsNullOrWhiteSpace(Layout), x => x.Layout == Layout) |
|||
.ToList(); |
|||
} |
|||
|
|||
layoutHooks ??= new List<LayoutHookInfo>(); |
|||
|
|||
LayoutHookViewModel = new LayoutHookViewModel(layoutHooks.ToArray(), Layout); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout; |
|||
|
|||
public static class StandardLayouts |
|||
{ |
|||
public const string Application = "Application"; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// This file is automatically generated by ABP framework to use MVC Controllers from CSharp
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Http.Client; |
|||
using Volo.Abp.Http.Modeling; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Http.Client.ClientProxying; |
|||
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
// ReSharper disable once CheckNamespace
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; |
|||
|
|||
[Dependency(ReplaceServices = true)] |
|||
[ExposeServices(typeof(IAbpApplicationLocalizationAppService), typeof(AbpApplicationLocalizationClientProxy))] |
|||
public partial class AbpApplicationLocalizationClientProxy : ClientProxyBase<IAbpApplicationLocalizationAppService>, IAbpApplicationLocalizationAppService |
|||
{ |
|||
public virtual async Task<ApplicationLocalizationDto> GetAsync(ApplicationLocalizationRequestDto input) |
|||
{ |
|||
return await RequestAsync<ApplicationLocalizationDto>(nameof(GetAsync), new ClientProxyRequestTypeValue |
|||
{ |
|||
{ typeof(ApplicationLocalizationRequestDto), input } |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
// This file is part of AbpApplicationLocalizationClientProxy, you can customize it here
|
|||
// ReSharper disable once CheckNamespace
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ClientProxies; |
|||
|
|||
public partial class AbpApplicationLocalizationClientProxy |
|||
{ |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Localization.External; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Client; |
|||
|
|||
public class RemoteExternalLocalizationStore : IExternalLocalizationStore, ITransientDependency |
|||
{ |
|||
protected ICachedApplicationConfigurationClient ConfigurationClient { get; } |
|||
protected AbpLocalizationOptions LocalizationOptions { get; } |
|||
|
|||
public RemoteExternalLocalizationStore( |
|||
ICachedApplicationConfigurationClient configurationClient, |
|||
IOptions<AbpLocalizationOptions> localizationOptions) |
|||
{ |
|||
ConfigurationClient = configurationClient; |
|||
LocalizationOptions = localizationOptions.Value; |
|||
} |
|||
|
|||
public virtual LocalizationResourceBase GetResourceOrNull(string resourceName) |
|||
{ |
|||
var configurationDto = ConfigurationClient.Get(); |
|||
return CreateLocalizationResourceFromConfigurationOrNull(resourceName, configurationDto); |
|||
} |
|||
|
|||
public virtual async Task<LocalizationResourceBase> GetResourceOrNullAsync(string resourceName) |
|||
{ |
|||
var configurationDto = await ConfigurationClient.GetAsync(); |
|||
return CreateLocalizationResourceFromConfigurationOrNull(resourceName, configurationDto); |
|||
} |
|||
|
|||
public virtual async Task<string[]> GetResourceNamesAsync() |
|||
{ |
|||
var configurationDto = await ConfigurationClient.GetAsync(); |
|||
return configurationDto |
|||
.Localization |
|||
.Resources |
|||
.Keys |
|||
.Where(x => !LocalizationOptions.Resources.ContainsKey(x)) |
|||
.ToArray(); |
|||
; } |
|||
|
|||
public virtual async Task<LocalizationResourceBase[]> GetResourcesAsync() |
|||
{ |
|||
var configurationDto = await ConfigurationClient.GetAsync(); |
|||
var resources = new List<LocalizationResourceBase>(); |
|||
|
|||
foreach (var resource in configurationDto.Localization.Resources) |
|||
{ |
|||
if (LocalizationOptions.Resources.ContainsKey(resource.Key)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
resources.Add(CreateNonTypedLocalizationResource(resource.Key, resource.Value)); |
|||
} |
|||
|
|||
return resources.ToArray(); |
|||
} |
|||
|
|||
protected virtual LocalizationResourceBase CreateLocalizationResourceFromConfigurationOrNull( |
|||
string resourceName, |
|||
ApplicationConfigurationDto configurationDto) |
|||
{ |
|||
var resourceDto = configurationDto.Localization.Resources.GetOrDefault(resourceName); |
|||
|
|||
if (resourceDto == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return CreateNonTypedLocalizationResource(resourceName, resourceDto); |
|||
} |
|||
|
|||
protected virtual NonTypedLocalizationResource CreateNonTypedLocalizationResource( |
|||
string resourceName, |
|||
ApplicationLocalizationResourceDto resourceDto) |
|||
{ |
|||
return new NonTypedLocalizationResource(resourceName) |
|||
.AddBaseResources(resourceDto.BaseResources); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
public class ApplicationConfigurationRequestOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Set to true to fill the Values property in <see cref="ApplicationConfigurationDto.Localization"/>.
|
|||
/// </summary>
|
|||
public bool IncludeLocalizationResources { get; set; } = true; |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
[Serializable] |
|||
public class ApplicationLocalizationDto |
|||
{ |
|||
public Dictionary<string, ApplicationLocalizationResourceDto> Resources { get; set; } |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
public class ApplicationLocalizationRequestDto |
|||
{ |
|||
[Required] |
|||
public string CultureName { get; set; } |
|||
|
|||
public bool OnlyDynamics { get; set; } |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
[Serializable] |
|||
public class ApplicationLocalizationResourceDto |
|||
{ |
|||
public Dictionary<string, string> Texts { get; set; } |
|||
|
|||
public string[] BaseResources { get; set; } |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
public interface IAbpApplicationLocalizationAppService : IApplicationService |
|||
{ |
|||
Task<ApplicationLocalizationDto> GetAsync(ApplicationLocalizationRequestDto input); |
|||
} |
|||
@ -0,0 +1,91 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Localization.External; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
public class AbpApplicationLocalizationAppService : |
|||
ApplicationService, |
|||
IAbpApplicationLocalizationAppService |
|||
{ |
|||
protected IExternalLocalizationStore ExternalLocalizationStore { get; } |
|||
protected AbpLocalizationOptions LocalizationOptions { get; } |
|||
|
|||
public AbpApplicationLocalizationAppService( |
|||
IExternalLocalizationStore externalLocalizationStore, |
|||
IOptions<AbpLocalizationOptions> localizationOptions) |
|||
{ |
|||
ExternalLocalizationStore = externalLocalizationStore; |
|||
LocalizationOptions = localizationOptions.Value; |
|||
} |
|||
|
|||
public async Task<ApplicationLocalizationDto> GetAsync(ApplicationLocalizationRequestDto input) |
|||
{ |
|||
using (CultureHelper.Use(input.CultureName)) |
|||
{ |
|||
var resources = LocalizationOptions |
|||
.Resources |
|||
.Values |
|||
.Union( |
|||
await ExternalLocalizationStore.GetResourcesAsync() |
|||
).ToArray(); |
|||
|
|||
var localizationConfig = new ApplicationLocalizationDto { |
|||
Resources = new Dictionary<string, ApplicationLocalizationResourceDto>(resources.Length) |
|||
}; |
|||
|
|||
foreach (var resource in resources) |
|||
{ |
|||
var dictionary = new Dictionary<string, string>(); |
|||
var localizer = await StringLocalizerFactory.CreateByResourceNameOrNullAsync(resource.ResourceName); |
|||
if (localizer != null) |
|||
{ |
|||
Dictionary<string, LocalizedString> staticLocalizedStrings = null; |
|||
|
|||
if (input.OnlyDynamics) |
|||
{ |
|||
staticLocalizedStrings = (await localizer.GetAllStringsAsync( |
|||
includeParentCultures: true, |
|||
includeBaseLocalizers: false, |
|||
includeDynamicContributors: false |
|||
)).ToDictionary(x => x.Name); |
|||
} |
|||
|
|||
var localizedStringsWithDynamics = await localizer.GetAllStringsAsync( |
|||
includeParentCultures: true, |
|||
includeBaseLocalizers: false, |
|||
includeDynamicContributors: true |
|||
); |
|||
|
|||
foreach (var localizedString in localizedStringsWithDynamics) |
|||
{ |
|||
if (input.OnlyDynamics) |
|||
{ |
|||
var staticLocalizedString = staticLocalizedStrings.GetOrDefault(localizedString.Name); |
|||
if (staticLocalizedString != null && |
|||
localizedString.Value == staticLocalizedString.Value) |
|||
{ |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
dictionary[localizedString.Name] = localizedString.Value; |
|||
} |
|||
} |
|||
|
|||
localizationConfig.Resources[resource.ResourceName] = |
|||
new ApplicationLocalizationResourceDto { |
|||
Texts = dictionary, |
|||
BaseResources = resource.BaseResourceNames.ToArray() |
|||
}; |
|||
} |
|||
|
|||
return localizationConfig; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
|
|||
[Area("abp")] |
|||
[RemoteService(Name = "abp")] |
|||
[Route("api/abp/application-localization")] |
|||
public class AbpApplicationLocalizationController: AbpControllerBase, IAbpApplicationLocalizationAppService |
|||
{ |
|||
private readonly IAbpApplicationLocalizationAppService _localizationAppService; |
|||
|
|||
public AbpApplicationLocalizationController(IAbpApplicationLocalizationAppService localizationAppService) |
|||
{ |
|||
_localizationAppService = localizationAppService; |
|||
} |
|||
|
|||
[HttpGet] |
|||
public virtual async Task<ApplicationLocalizationDto> GetAsync(ApplicationLocalizationRequestDto input) |
|||
{ |
|||
return await _localizationAppService.GetAsync(input); |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
using System; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Localization; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; |
|||
using Volo.Abp.Auditing; |
|||
using Volo.Abp.Http; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Minify.Scripts; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.Localization; |
|||
|
|||
[Area("Abp")] |
|||
[Route("Abp/ApplicationLocalizationScript")] |
|||
[DisableAuditing] |
|||
[RemoteService(false)] |
|||
[ApiExplorerSettings(IgnoreApi = true)] |
|||
public class AbpApplicationLocalizationScriptController : AbpController |
|||
{ |
|||
protected AbpApplicationLocalizationAppService LocalizationAppService { get; } |
|||
protected AbpAspNetCoreMvcOptions Options { get; } |
|||
protected IJsonSerializer JsonSerializer { get; } |
|||
protected IJavascriptMinifier JavascriptMinifier { get; } |
|||
|
|||
public AbpApplicationLocalizationScriptController( |
|||
AbpApplicationLocalizationAppService localizationAppService, |
|||
IOptions<AbpAspNetCoreMvcOptions> options, |
|||
IJsonSerializer jsonSerializer, |
|||
IJavascriptMinifier javascriptMinifier) |
|||
{ |
|||
LocalizationAppService = localizationAppService; |
|||
JsonSerializer = jsonSerializer; |
|||
JavascriptMinifier = javascriptMinifier; |
|||
Options = options.Value; |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Produces(MimeTypes.Application.Javascript, MimeTypes.Text.Plain)] |
|||
public async Task<ActionResult> GetAsync(ApplicationLocalizationRequestDto input) |
|||
{ |
|||
var script = CreateScript( |
|||
await LocalizationAppService.GetAsync(input) |
|||
); |
|||
|
|||
return Content( |
|||
Options.MinifyGeneratedScript == true |
|||
? JavascriptMinifier.Minify(script) |
|||
: script, |
|||
MimeTypes.Application.Javascript |
|||
); |
|||
} |
|||
|
|||
private string CreateScript(ApplicationLocalizationDto localizationDto) |
|||
{ |
|||
var script = new StringBuilder(); |
|||
|
|||
script.AppendLine("(function(){"); |
|||
script.AppendLine(); |
|||
script.AppendLine( |
|||
$"$.extend(true, abp.localization, {JsonSerializer.Serialize(localizationDto, indented: true)})"); |
|||
script.AppendLine(); |
|||
script.Append("})();"); |
|||
|
|||
return script.ToString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
namespace Volo.Abp.DistributedLocking; |
|||
|
|||
public class AbpDistributedLockOptions |
|||
{ |
|||
/// <summary>
|
|||
/// DistributedLock key prefix.
|
|||
/// </summary>
|
|||
public string KeyPrefix { get; set; } |
|||
|
|||
public AbpDistributedLockOptions() |
|||
{ |
|||
KeyPrefix = ""; |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.DistributedLocking; |
|||
|
|||
public class DistributedLockKeyNormalizer : IDistributedLockKeyNormalizer, ITransientDependency |
|||
{ |
|||
protected AbpDistributedLockOptions Options { get; } |
|||
|
|||
public DistributedLockKeyNormalizer(IOptions<AbpDistributedLockOptions> options) |
|||
{ |
|||
Options = options.Value; |
|||
} |
|||
|
|||
public virtual string NormalizeKey(string name) |
|||
{ |
|||
return $"{Options.KeyPrefix}{name}"; |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.DistributedLocking; |
|||
|
|||
public interface IDistributedLockKeyNormalizer |
|||
{ |
|||
string NormalizeKey(string name); |
|||
|
|||
} |
|||
@ -1,10 +1,66 @@ |
|||
namespace Microsoft.Extensions.Localization; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp; |
|||
|
|||
namespace Microsoft.Extensions.Localization; |
|||
|
|||
public static class AbpStringLocalizerFactoryExtensions |
|||
{ |
|||
[CanBeNull] |
|||
public static IStringLocalizer CreateDefaultOrNull(this IStringLocalizerFactory localizerFactory) |
|||
{ |
|||
return (localizerFactory as IAbpStringLocalizerFactoryWithDefaultResourceSupport) |
|||
return (localizerFactory as IAbpStringLocalizerFactory) |
|||
?.CreateDefaultOrNull(); |
|||
} |
|||
|
|||
[CanBeNull] |
|||
public static IStringLocalizer CreateByResourceNameOrNull( |
|||
this IStringLocalizerFactory localizerFactory, |
|||
string resourceName) |
|||
{ |
|||
return (localizerFactory as IAbpStringLocalizerFactory) |
|||
?.CreateByResourceNameOrNull(resourceName); |
|||
} |
|||
|
|||
[NotNull] |
|||
public static IStringLocalizer CreateByResourceName( |
|||
this IStringLocalizerFactory localizerFactory, |
|||
string resourceName) |
|||
{ |
|||
var localizer = localizerFactory.CreateByResourceNameOrNull(resourceName); |
|||
if (localizer == null) |
|||
{ |
|||
throw new AbpException("Couldn't find a localizer with given resource name: " + resourceName); |
|||
} |
|||
|
|||
return localizer; |
|||
} |
|||
|
|||
[ItemCanBeNull] |
|||
public static async Task<IStringLocalizer> CreateByResourceNameOrNullAsync( |
|||
this IStringLocalizerFactory localizerFactory, |
|||
string resourceName) |
|||
{ |
|||
var abpLocalizerFactory = localizerFactory as IAbpStringLocalizerFactory; |
|||
if (abpLocalizerFactory == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return await abpLocalizerFactory.CreateByResourceNameOrNullAsync(resourceName); |
|||
} |
|||
|
|||
[NotNull] |
|||
public async static Task<IStringLocalizer> CreateByResourceNameAsync( |
|||
this IStringLocalizerFactory localizerFactory, |
|||
string resourceName) |
|||
{ |
|||
var localizer = await localizerFactory.CreateByResourceNameOrNullAsync(resourceName); |
|||
if (localizer == null) |
|||
{ |
|||
throw new AbpException("Couldn't find a localizer with given resource name: " + resourceName); |
|||
} |
|||
|
|||
return localizer; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,16 @@ |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Microsoft.Extensions.Localization; |
|||
|
|||
public interface IAbpStringLocalizerFactory |
|||
{ |
|||
[CanBeNull] |
|||
IStringLocalizer CreateDefaultOrNull(); |
|||
|
|||
[CanBeNull] |
|||
IStringLocalizer CreateByResourceNameOrNull([NotNull] string resourceName); |
|||
|
|||
[ItemCanBeNull] |
|||
Task<IStringLocalizer> CreateByResourceNameOrNullAsync([NotNull] string resourceName); |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Microsoft.Extensions.Localization; |
|||
|
|||
public interface IAbpStringLocalizerFactoryWithDefaultResourceSupport |
|||
{ |
|||
[CanBeNull] |
|||
IStringLocalizer CreateDefaultOrNull(); |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Localization; |
|||
|
|||
namespace Volo.Abp.Localization; |
|||
|
|||
public interface IAsyncLocalizableString |
|||
{ |
|||
Task<LocalizedString> LocalizeAsync(IStringLocalizerFactory stringLocalizerFactory); |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Localization; |
|||
|
|||
namespace Volo.Abp.Localization; |
|||
|
|||
public static class LocalizableStringExtensions |
|||
{ |
|||
public static async Task<LocalizedString> LocalizeAsync( |
|||
this ILocalizableString localizableString, |
|||
IStringLocalizerFactory stringLocalizerFactory) |
|||
{ |
|||
if (localizableString is IAsyncLocalizableString asyncLocalizableString) |
|||
{ |
|||
return await asyncLocalizableString.LocalizeAsync(stringLocalizerFactory); |
|||
} |
|||
|
|||
return localizableString.Localize(stringLocalizerFactory); |
|||
} |
|||
} |
|||