Quantcast
Channel: ASP.NET Core
Viewing all articles
Browse latest Browse all 9386

How to create localized routes and language selector

$
0
0

Hi all,

There are 3 things I would like to do :

  1. Create localized routes likes : www.mywebsite.com/fr/controller/action/ hiding culture in URL if default culture (EN) www.mywebsite.com/controller/action/
  2. Save user culture preference in a cookie to get it automatically used on the next visit
  3. Create the language selector

I can make these 3 points working separately but I am not able to use all of them together. I don't really know how to proceed. (using controller or filter...)

For the routes I did the below, seems to be working except that default language still appear in the url. Seems not really clean to me, quite sure there is better way to achieve that.

public class CultureFilter : IRequestCultureProvider
{
    private readonly CultureInfo defaultCulture;
    private readonly CultureInfo defaultUICulture;

    public CultureFilter(RequestCulture requestCulture)
    {
        this.defaultCulture = requestCulture.Culture;
        this.defaultUICulture = requestCulture.UICulture;
    }

    public Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
    {
        //Parsing language from url path, which looks like "/en/home/index"
        PathString url = httpContext.Request.Path;

        // Test any culture in route
        if (url.ToString().Length <= 1)
        {
            // Set default Culture and default UICulture
            return Task.FromResult<ProviderCultureResult>(new ProviderCultureResult(this.defaultCulture.TwoLetterISOLanguageName, this.defaultUICulture.TwoLetterISOLanguageName));
        }

        var parts = httpContext.Request.Path.Value.Split('/');
        var culture = parts[1];

        // Test if the culture is properly formatted
        if (!Regex.IsMatch(culture, @"^[a-z]{2}(-[A-Z]{2})*$"))
        {
            // Set default Culture and default UICulture
            return Task.FromResult<ProviderCultureResult>(new ProviderCultureResult(this.defaultCulture.TwoLetterISOLanguageName, this.defaultUICulture.TwoLetterISOLanguageName));
        }

        // Set Culture and UICulture from route culture parameter
        return Task.FromResult<ProviderCultureResult>(new ProviderCultureResult(culture, culture));
    }
}

For the cookie, I add the idea to use a controller called within my language selector, but again, quite sure this is not the right way to do that. And my cookie value is quite strange.

Maybe a simple filter would be enough to handle these 3 points ?

public class CultureController : Controller
{
    [HttpPost]
    public IActionResult SelectCulture(string culture, string returnUrl)
    {
        Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
            new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
        );

        return LocalRedirect(returnUrl);
    }
}

Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRouting(options => options.LowercaseUrls = true);
        services.AddLocalization(options => options.ResourcesPath = "Resources");

        services
            .AddControllersWithViews()
            .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
            .AddDataAnnotationsLocalization();

        services.Configure<RequestLocalizationOptions>(options =>
        {
            var cultures = new[]
            {
                new CultureInfo("en"),
                new CultureInfo("fr"),
                new CultureInfo("es")
            };
            options.DefaultRequestCulture = new RequestCulture(culture: "en", uiCulture: "en");
            options.SupportedCultures = cultures;
            options.SupportedUICultures = cultures;

            options.RequestCultureProviders.Insert(0, new CultureFilter(options.DefaultRequestCulture));
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRequestLocalization();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Static/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "localization",
                pattern: "{culture=en}/{controller=Static}/{action=Index}/{id?}");
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Static}/{action=Index}/{id?}");
        });
    }
}

Thanks for your help !


Viewing all articles
Browse latest Browse all 9386

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>