Browse Source

feat: Enhance URL-based culture handling with new interfaces and async methods

pull/25174/head
maliming 7 months ago
parent
commit
6895d24d5a
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 8
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/AbpWasmCultureMenuItemUrlProvider.cs
  2. 14
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/IRouteBasedCultureUrlHelper.cs
  3. 34
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/RouteBasedCultureUrlHelper.cs
  4. 15
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpCultureMenuItemUrlProvider.cs
  5. 5
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs
  6. 8
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IMenuItemCulturePrefixHelper.cs
  7. 13
      framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuItemCulturePrefixHelper.cs
  8. 36
      modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs

8
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/AbpWasmCultureMenuItemUrlProvider.cs

@ -14,11 +14,14 @@ namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming;
public class AbpWasmCultureMenuItemUrlProvider : IMenuItemUrlProvider, ITransientDependency
{
protected ICachedApplicationConfigurationClient ConfigurationClient { get; }
protected IMenuItemCulturePrefixHelper MenuItemCulturePrefixHelper { get; }
public AbpWasmCultureMenuItemUrlProvider(
ICachedApplicationConfigurationClient configurationClient)
ICachedApplicationConfigurationClient configurationClient,
IMenuItemCulturePrefixHelper menuItemCulturePrefixHelper)
{
ConfigurationClient = configurationClient;
MenuItemCulturePrefixHelper = menuItemCulturePrefixHelper;
}
public virtual async Task HandleAsync(MenuItemUrlProviderContext context)
@ -40,7 +43,7 @@ public class AbpWasmCultureMenuItemUrlProvider : IMenuItemUrlProvider, ITransien
return;
}
MenuItemCulturePrefixHelper.PrependCulturePrefix(context.Menu, "/" + culture);
await MenuItemCulturePrefixHelper.PrependCulturePrefixAsync(context.Menu, "/" + culture);
}
protected virtual string? GetCulture(Mvc.ApplicationConfigurations.ApplicationConfigurationDto config)
@ -57,5 +60,4 @@ public class AbpWasmCultureMenuItemUrlProvider : IMenuItemUrlProvider, ITransien
return isKnownCulture ? currentCulture : null;
}
}

14
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/IRouteBasedCultureUrlHelper.cs

@ -0,0 +1,14 @@
using System.Threading.Tasks;
namespace Volo.Abp.AspNetCore.Components.WebAssembly;
public interface IRouteBasedCultureUrlHelper
{
/// <summary>
/// Prepends the current culture to <paramref name="url"/> when route-based culture is enabled
/// and the current culture is a known application language.
/// Returns the original <paramref name="url"/> unchanged when the feature is disabled or the
/// culture is not recognised.
/// </summary>
Task<string> PrependCulturePrefixAsync(string url);
}

34
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/RouteBasedCultureUrlHelper.cs

@ -0,0 +1,34 @@
using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.Client;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.WebAssembly;
public class RouteBasedCultureUrlHelper : IRouteBasedCultureUrlHelper, ITransientDependency
{
private readonly ICachedApplicationConfigurationClient _configurationClient;
public RouteBasedCultureUrlHelper(ICachedApplicationConfigurationClient configurationClient)
{
_configurationClient = configurationClient;
}
public virtual async Task<string> PrependCulturePrefixAsync(string url)
{
var config = await _configurationClient.GetAsync();
if (config?.Localization.UseRouteBasedCulture != true)
{
return url;
}
var currentCulture = CultureInfo.CurrentCulture.Name;
var isKnownCulture = config.Localization.Languages
.Any(l => string.Equals(l.CultureName, currentCulture, StringComparison.OrdinalIgnoreCase));
return isKnownCulture ? $"{currentCulture}/{url}" : url;
}
}

15
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Localization/AbpCultureMenuItemUrlProvider.cs

@ -20,33 +20,34 @@ public class AbpCultureMenuItemUrlProvider : IMenuItemUrlProvider, ITransientDep
protected IHttpContextAccessor HttpContextAccessor { get; }
protected IOptions<AbpRequestLocalizationOptions> LocalizationOptions { get; }
protected IOptions<AbpLocalizationOptions> AbpLocalizationOptions { get; }
protected IMenuItemCulturePrefixHelper MenuItemCulturePrefixHelper { get; }
public AbpCultureMenuItemUrlProvider(
IHttpContextAccessor httpContextAccessor,
IOptions<AbpRequestLocalizationOptions> localizationOptions,
IOptions<AbpLocalizationOptions> abpLocalizationOptions)
IOptions<AbpLocalizationOptions> abpLocalizationOptions,
IMenuItemCulturePrefixHelper menuItemCulturePrefixHelper)
{
HttpContextAccessor = httpContextAccessor;
LocalizationOptions = localizationOptions;
AbpLocalizationOptions = abpLocalizationOptions;
MenuItemCulturePrefixHelper = menuItemCulturePrefixHelper;
}
public virtual Task HandleAsync(MenuItemUrlProviderContext context)
public virtual async Task HandleAsync(MenuItemUrlProviderContext context)
{
if (!LocalizationOptions.Value.UseRouteBasedCulture)
{
return Task.CompletedTask;
return;
}
var culture = GetCulture();
if (string.IsNullOrEmpty(culture))
{
return Task.CompletedTask;
return;
}
MenuItemCulturePrefixHelper.PrependCulturePrefix(context.Menu, "/" + culture);
return Task.CompletedTask;
await MenuItemCulturePrefixHelper.PrependCulturePrefixAsync(context.Menu, "/" + culture);
}
protected virtual string? GetCulture()

5
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/RequestLocalization/AbpRequestLocalizationMiddleware.cs

@ -54,8 +54,11 @@ public class AbpRequestLocalizationMiddleware : AbpMiddlewareBase, ITransientDep
// This cookie is used by AbpCultureMenuItemUrlProvider to determine if the
// initial SSR page had a culture prefix, since the Blazor interactive circuit
// (/_blazor) does not carry the original route values.
// Note: ComponentTypeMetadata is an internal ASP.NET Core type
// (Microsoft.AspNetCore.Components.Endpoints.ComponentTypeMetadata).
// We match by full type name to avoid false positives from other assemblies.
var endpoint = context.GetEndpoint();
if (endpoint?.Metadata.Any(m => m.GetType().Name == "ComponentTypeMetadata") == true)
if (endpoint?.Metadata.Any(m => m.GetType().FullName == "Microsoft.AspNetCore.Components.Endpoints.ComponentTypeMetadata") == true)
{
AbpRequestCultureCookieHelper.SetHasRouteCultureCookie(
context, requestCultureFeature?.Provider is RouteDataRequestCultureProvider);

8
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IMenuItemCulturePrefixHelper.cs

@ -0,0 +1,8 @@
using System.Threading.Tasks;
namespace Volo.Abp.UI.Navigation;
public interface IMenuItemCulturePrefixHelper
{
Task PrependCulturePrefixAsync(IHasMenuItems menuWithItems, string prefix);
}

13
framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuItemCulturePrefixHelper.cs

@ -1,8 +1,17 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.UI.Navigation;
public static class MenuItemCulturePrefixHelper
public class MenuItemCulturePrefixHelper : IMenuItemCulturePrefixHelper, ITransientDependency
{
public static void PrependCulturePrefix(IHasMenuItems menuWithItems, string prefix)
public virtual Task PrependCulturePrefixAsync(IHasMenuItems menuWithItems, string prefix)
{
PrependCulturePrefix(menuWithItems, prefix);
return Task.CompletedTask;
}
protected virtual void PrependCulturePrefix(IHasMenuItems menuWithItems, string prefix)
{
foreach (var item in menuWithItems.Items)
{

36
modules/basic-theme/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/LoginDisplay.razor.cs

@ -1,14 +1,11 @@
using System;
using System.Globalization;
using System.Linq;
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.JSInterop;
using Volo.Abp.AspNetCore.Components.Web.Security;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.AspNetCore.Mvc.Client;
using Volo.Abp.AspNetCore.Components.WebAssembly;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic;
@ -22,33 +19,18 @@ public partial class LoginDisplay : IDisposable
protected ApplicationConfigurationChangedService ApplicationConfigurationChangedService { get; set; }
[Inject]
protected ICachedApplicationConfigurationClient ConfigurationClient { get; set; }
protected IRouteBasedCultureUrlHelper CultureUrlHelper { get; set; }
protected ApplicationMenu Menu { get; set; }
private ApplicationConfigurationDto _config;
protected string LoginUrl { get; set; } = string.Empty;
protected string LoginUrl => PrependCulturePrefix(AuthenticationOptions.Value.LoginUrl);
protected string LogoutUrl => PrependCulturePrefix(AuthenticationOptions.Value.LogoutUrl);
protected string PrependCulturePrefix(string url)
{
if (_config?.Localization.UseRouteBasedCulture != true)
{
return url;
}
var currentCulture = CultureInfo.CurrentCulture.Name;
var isKnownCulture = _config.Localization.Languages
.Any(l => string.Equals(l.CultureName, currentCulture, StringComparison.OrdinalIgnoreCase));
return isKnownCulture ? $"{currentCulture}/{url}" : url;
}
protected string LogoutUrl { get; set; } = string.Empty;
protected async override Task OnInitializedAsync()
{
_config = await ConfigurationClient.GetAsync();
LoginUrl = await CultureUrlHelper.PrependCulturePrefixAsync(AuthenticationOptions.Value.LoginUrl);
LogoutUrl = await CultureUrlHelper.PrependCulturePrefixAsync(AuthenticationOptions.Value.LogoutUrl);
Menu = await MenuManager.GetAsync(StandardMenus.User);
@ -64,6 +46,8 @@ public partial class LoginDisplay : IDisposable
private async void ApplicationConfigurationChanged()
{
LoginUrl = await CultureUrlHelper.PrependCulturePrefixAsync(AuthenticationOptions.Value.LoginUrl);
LogoutUrl = await CultureUrlHelper.PrependCulturePrefixAsync(AuthenticationOptions.Value.LogoutUrl);
Menu = await MenuManager.GetAsync(StandardMenus.User);
await InvokeAsync(StateHasChanged);
}
@ -88,7 +72,7 @@ public partial class LoginDisplay : IDisposable
}
}
private void BeginSignOut()
private async Task BeginSignOut()
{
if (AbpAspNetCoreComponentsWebOptions.Value.IsBlazorWebApp)
{

Loading…
Cancel
Save