Setting page culture based on route parameter

70 views Asked by At

Using .NET Core 7, I need to set a page's culture using the route parameter culture:

builder.Services
       .AddRazorPages()
       .AddViewLocalization(x => x.ResourcesPath = builder.Environment.WebRootPath);

builder.Services.Configure<RequestLocalizationOptions>(x => {
  x.AddSupportedCultures("pt", "en");
  x.AddSupportedUICultures("pt", "en");
  x.SetDefaultCulture("pt");
  x.RequestCultureProviders.Clear();
  x.AddInitialRequestCultureProvider(new RouteDataRequestCultureProvider { RouteDataStringKey = "culture" });
});

builder.Services.Configure<RouteOptions>(x => {  
  x.ConstraintMap.Add("culture", typeof(CultureRouteConstraint));  
}); 

application
  .UseRouting()
  .UseRequestLocalization();

The CultureRouteConstraint is the following:

public class CultureRouteConstraint : IRouteConstraint 
{
    private readonly RequestLocalizationOptions _options;

    public CultureRouteConstraint(IOptions<RequestLocalizationOptions> options) 
    {
        _options = options.Value;
    } 

    public Boolean Match(HttpContext? httpContext, IRouter? route, String routeKey, RouteValueDictionary values, RouteDirection routeDirection) 
    {
        if (routeKey == null) 
           throw new ArgumentNullException(nameof(routeKey));
    
        if (values == null) 
           throw new ArgumentNullException(nameof(values));

        if (values.TryGetValue(routeKey, out var value) && value != null) 
        {
            String? culture = Convert.ToString(value, CultureInfo.InvariantCulture);
            List<String>? cultures = _options.SupportedCultures?.Select(x => x.TwoLetterISOLanguageName).ToList();

            if (culture != null && cultures != null)
                return cultures.Contains(culture, StringComparer.InvariantCultureIgnoreCase);
        }

        return false;
    } 
} 

I have 2 pages (Index and About) which Razor pages routes are:

Index: @page "/{culture}"
About: @page "/{culture}/about"

When I access an URL such as:

http://localhost:5000/en/about
http://localhost:5000/pt/about

The culture is set to the correct value.

When I access the same url without the culture route parameter:

http://localhost:5000/about

the culture is set to the default value, e.g., pt.

But when I access the homepage without the culture route parameter:

http://localhost:5000

I am redirected to:

http://localhost:5000/en

However en is not the default culture. pt is ...

Why does this happen?

Note:

I have breakpoints in CultureRouteConstraint and they are never hit.

Am I missing something?

Update

The full Program.cs:

  WebApplicationBuilder builder = WebApplication.CreateBuilder(new WebApplicationOptions { 
    Args = args, 
    ApplicationName = typeof(Program).Assembly.FullName,
    ContentRootPath = Directory.GetCurrentDirectory(),
    WebRootPath = "webroot"
  });

  builder.Services.AddLocalization(x => x.ResourcesPath = builder.Environment.WebRootPath);

  builder.Services
    .AddRazorPages()
    .AddViewLocalization(x => x.ResourcesPath = builder.Environment.WebRootPath);

  builder.Services.Configure<RequestLocalizationOptions>(x => {
    x.AddSupportedCultures("pt", "en");
    x.AddSupportedUICultures("pt", "en");
    x.SetDefaultCulture("pt");
    x.RequestCultureProviders.Clear();
    x.AddInitialRequestCultureProvider(new RouteDataRequestCultureProvider { RouteDataStringKey = "culture" });
  });

  builder.Services.Configure<RouteOptions>(x => {  
    x.ConstraintMap.Add("culture", typeof(CultureRouteConstraint));  
  }); 

  builder.Services.AddValidatorsFromAssemblyContaining<Program>(); 

  builder.Services.AddResponseCaching(x => { x.UseCaseSensitivePaths = false; x.MaximumBodySize = 2097152; });

  builder.Services.AddHealthChecks();

  builder.Services.Configure<AppOptions>(builder.Configuration);

  WebApplication application = builder.Build();

  application
    .UseRewriter(new RewriteOptions()
    .AddRedirect(@"^$", $"pt", StatusCodes.Status301MovedPermanently)
    );

  application.UseStatusCodePagesWithReExecute("/error/{0}");

  application.UseStaticFiles();

  application
    .UseRouting()
    .UseRequestLocalization();

  application.MapRazorPages();

  application.UseResponseCaching();

  application.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = HealthChecksResponse.Write });

  application.Run();
0

There are 0 answers