Coder Social home page Coder Social logo

Comments (6)

Dresel avatar Dresel commented on July 17, 2024

I can't reproduce this.

I have used your setup from your previous issue:

// Configure localization
services.AddSingleton(provider =>
{
    RequestLocalizationOptions requestLocalizationOptions = new RequestLocalizationOptions()
    {
        DefaultRequestCulture = new RequestCulture("en"),

        // Formatting numbers, dates, etc.
        SupportedCultures = new[] { new CultureInfo("en"), new CultureInfo("pt") },

        // UI strings that we have localized.
        SupportedUICultures = new[] { new CultureInfo("en"), new CultureInfo("pt") },
    };

    // Replaces CultureSensitiveActionFilterAttribute
    requestLocalizationOptions.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());

    return requestLocalizationOptions;
});

// Add framework services.
services
    .AddMvc(x => { x.Filters.Add(new MiddlewareFilterAttribute(typeof(LocalizationPipeline))); })
    .AddRouteLocalization(x =>
    {
        x.UseCulture("en")
            .WhereUntranslated()
            .AddDefaultTranslation();

        x.UseCulture("pt")
            .WhereController(nameof(HomeController))
            .WhereAction(nameof(HomeController.Index))
            .TranslateAction("");

        x.UseCulture("pt")
            .WhereController(nameof(AboutController))
            .WhereAction(nameof(AboutController.Index))
            .TranslateAction("quem-somos");

    })
    .AddTypedRouting()
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();

services.AddSingleton(x => {
    RequestLocalizationOptions requestLocalizationOptions = new RequestLocalizationOptions()
    {
        DefaultRequestCulture = new RequestCulture("en"),
        SupportedCultures = new[] { new CultureInfo("en"), new CultureInfo("pt") },
        SupportedUICultures = new[] { new CultureInfo("en"), new CultureInfo("pt") },
    };
    requestLocalizationOptions.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
    return requestLocalizationOptions;
});

services.Configure<MvcOptions>(options => options.Conventions.Add(new CollectRoutesApplicationConvention()));

and

@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Routing
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width"/>
    <title>RouteLocalization.MVC.Sample</title>
</head>
<body>
<div>
    @RenderBody()
</div>
<div>
    <div>Current Culture: @(Context.Features.Get<IRequestCultureFeature>().RequestCulture.UICulture.Name)</div>
    <div>Current localized Route: @Url.RouteUrl(ViewContext.RouteData.Values)</div>
    @{
        RouteValueDictionary routeValueDictionary = new RouteValueDictionary(ViewContext.RouteData.Values);
        routeValueDictionary["culture"] = null;

        <div>Original version of this route: <a href="@Url.RouteUrl(routeValueDictionary)">@(Url.RouteUrl(routeValueDictionary) ?? "[null]")</a>
        </div>
    }
    @{
        RouteValueDictionary routeValueDictionaryEN = new RouteValueDictionary(ViewContext.RouteData.Values);
        routeValueDictionaryEN["culture"] = "en";

        <div>English (en) version of this route: <a href="@Url.RouteUrl(routeValueDictionaryEN)">@(Url.RouteUrl(routeValueDictionaryEN) ?? "[null]")</a>
        </div>
    }
    @{
        RouteValueDictionary routeValueDictionaryPT = new RouteValueDictionary(ViewContext.RouteData.Values);
        routeValueDictionaryPT["culture"] = "pt";

        <div>German (de) version of this route: <a href="@Url.RouteUrl(routeValueDictionaryPT)">@(Url.RouteUrl(routeValueDictionaryPT) ?? "[null]")</a>
        </div>
    }
    <p>
        <strong>All discovered Routes:</strong>
    </p>
    <p>
        @foreach (string route in CollectRoutesApplicationConvention.Routes)
        {
            <div>@route</div>
        }
    </p>
</div>
</body>
</html>

Calling translated Urls works fine. Which Url causes this error? How does the rest of your configuration look like?

from routelocalization.

mdmoura avatar mdmoura commented on July 17, 2024

@Dresel I tried to change culture in all pages and got the same error in all of them. Here is my full configuration:

  public class Startup {

    public IConfiguration Configuration { get; }

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

    public void Configure(IApplicationBuilder applicationBuilder, IHostingEnvironment hostingEnvironment) {

      StaticFileOptions staticFileOptions = new StaticFileOptions();
      RewriteOptions rewriteOptions = new RewriteOptions();        

      if (hostingEnvironment.IsDevelopment()) {
        applicationBuilder.UseDeveloperExceptionPage();
        staticFileOptions.ContentTypeProvider = new FileExtensionContentTypeProvider()
          .With(x => {
            x.Mappings.With(y => {
              y.Add(".less", "text/css");
            });
            return x;
          });        
      } else { 
        applicationBuilder.UseStatusCodePagesWithReExecute("/errors/{0}");
      }

      applicationBuilder.UseRequestLocalization();

      applicationBuilder
        .UseRewriter(rewriteOptions)
        .UseStaticFiles(staticFileOptions);      

      applicationBuilder
        .UseMvc(routes => { routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); });

    } // Configure  

    public void ConfigureServices(IServiceCollection services) {          

      services
        .AddMvc(x => { x.Filters.Add(new MiddlewareFilterAttribute(typeof(LocalizationPipeline))); })
				.AddTypedRouting()
				.AddRouteLocalization(x => {
         x.UseCulture("pt").WhereController(nameof(HomeController)).WhereAction(nameof(HomeController.Index)).TranslateAction("");
					x.UseCulture("pt").WhereController(nameof(AboutController)).WhereAction(nameof(AboutController.Index)).TranslateAction("quem-somos");
          x.UseCulture("pt").WhereController(nameof(ContactController)).WhereAction(nameof(ContactController.Index)).TranslateAction("contactos");
          x.UseCulture("pt").WhereController(nameof(NewsController)).WhereAction(nameof(NewsController.Index)).TranslateAction("noticias");
          x.UseCulture("pt").WhereController(nameof(WhyPortugalController)).WhereAction(nameof(WhyPortugalController.Index)).TranslateAction("porque-portugal");
          x.UseCulture("pt").WhereController(nameof(ServiceController))
            .WhereAction(nameof(ServiceController.FamilyLifeAndLeisure)).TranslateAction("servicos/lazer-e-familia")
            .WhereAction(nameof(ServiceController.FinancialWealthPlanningAndManagement)).TranslateAction("servicos/planeamento-financeiro")
            .WhereAction(nameof(ServiceController.RealEstateConsultingAndAdvisory)).TranslateAction("servicos/assessoria-imobiliaria")
            .WhereAction(nameof(ServiceController.ResidenceAndCitizenshipPlanning)).TranslateAction("servicos/residencia-e-nacionalidade")
            .WhereAction(nameof(ServiceController.TaxConsulting)).TranslateAction("servicos/assessoria-fiscal");         
          
        })          
        .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
        .AddDataAnnotationsLocalization();    

      services.AddPortableObjectLocalization(x => x.ResourcesPath = "wwwroot/assets");                 

      services.AddRouting(x => { x.AppendTrailingSlash = false; x.LowercaseUrls = true; });

      services.AddAntiforgery(x => { x.Cookie.Name = "_antiforg"; x.FormFieldName = "_antiforg"; });

      services.AddOptions();

      services.Configure<Settings>(Configuration);         
     
     services.AddSingleton(x => {

	RequestLocalizationOptions requestLocalizationOptions = new RequestLocalizationOptions() {        
	   DefaultRequestCulture = new RequestCulture("en"),
           SupportedCultures = new[] { new CultureInfo("en"), new CultureInfo("pt") },
           SupportedUICultures = new[] { new CultureInfo("en"), new CultureInfo("pt") },
       };

	requestLocalizationOptions.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());

	return requestLocalizationOptions;

      });

      services.AddSingleton<IConfiguration>(Configuration);      

      services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
      services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();      
      
      services.AddTransient<IUrlHelperFactory, UrlHelperFactory>();
      services.AddTransient<IUrlHelper, UrlHelper>(x => (UrlHelper)x.GetService<IUrlHelperFactory>().GetUrlHelper(x.GetService<IActionContextAccessor>().ActionContext));      

      services.AddTransient<IMailService, MailService>();    

      services.AddScoped<IValidationService, ValidationService>();

      services.AddScoped<SingleInstanceFactory>(x => y => x.GetService(y));
      services.AddScoped<MultiInstanceFactory>(x => y => x.GetServices(y));

      services
        .Scan(x =>
          x.FromAssembliesOf(typeof(IMediator), typeof(Startup))
            .AddClasses(y => y.AssignableTo(typeof(IMediator))).AsImplementedInterfaces().WithScopedLifetime()            
            .AddClasses(y => y.AssignableTo(typeof(IRequestHandler<,>))).AsImplementedInterfaces().WithScopedLifetime()            
            .AddClasses(y => y.AssignableTo(typeof(IAsyncRequestHandler<,>))).AsImplementedInterfaces().WithScopedLifetime()
            .AddClasses(y => y.AssignableTo(typeof(INotificationHandler<>))).AsImplementedInterfaces().WithScopedLifetime()
            .AddClasses(y => y.AssignableTo(typeof(IAsyncNotificationHandler<>))).AsImplementedInterfaces().WithScopedLifetime());      

      services.Scan(x => x.FromAssembliesOf(typeof(Startup)).AddClasses(y => y.AssignableTo(typeof(IValidator))).AsImplementedInterfaces().WithScopedLifetime());

    } // ConfigureServices  

  } // Startup

Does this help?

from routelocalization.

Dresel avatar Dresel commented on July 17, 2024

Can you access translated routes directly by entering in browser bar (like /pt/quem-somos)?

Do you use the RouteValueDictionary anywhere else? It sounds like you add the culture key twice...

Either upload a repo or tell me what to add to the sample project to reproduce your error or uncomment parts of your config until it works and you can isolate the problem.

from routelocalization.

mdmoura avatar mdmoura commented on July 17, 2024

I found the problem but not sure what I am doing wrong. I was trying to create links to change the culture but using only one line of code so I used:

<a href="@(Url.RouteUrl(new RouteValueDictionary(ViewContext.RouteData.Values).With(x => { x.Add("culture", null); return x; })))">EN</a>
<a href="@(Url.RouteUrl(new RouteValueDictionary(ViewContext.RouteData.Values).With(x => { x.Add("culture", "pt"); return x; })))">PT</a>

With is a simple extension which code is the following:

public static void With(this T value, Action action) {
action(value);
}

public static R With<T, R>(this T value, Func<T, R> function) {
  return function(value);
}

I was able to solve it by using

x["culture"] = null

And

x["culture"] = "pt"

Do you have a shorter way than what you use in your sample to generate culture change links?

from routelocalization.

Dresel avatar Dresel commented on July 17, 2024

Well we are generating routes by passing route values (controller, action, culture, ...). To create a change culture link for the current link we need the current route values and change the culture to the culture we want.

One option to get the current route values is ViewContext.RouteData.Values. If you are on a translated route then there is already a culture (en for example) in this dictionary, so calling Add throws the exception above. That's why it's better to use the indexer dictionary[key] for adding / setting the culture value.

I don't know any "shorter" way, but if you want to keep your views clean, you could create an extension method for UrlHelper:

public static class UrlHelperExtension
{
    public static string RouteUrlWithCulture(this IUrlHelper urlHelper, string culture)
    {
        var routeValueDictionary = new RouteValueDictionary(urlHelper.ActionContext.RouteData.Values);
        routeValueDictionary["culture"] = culture;

        return urlHelper.RouteUrl(routeValueDictionary);
    }
}

and use it within your view:

<div><a href="@Url.RouteUrlWithCulture("pt")">Change Culture</a></div>

Does this help you?

from routelocalization.

mdmoura avatar mdmoura commented on July 17, 2024

Yes it does. Thank you for the help.

from routelocalization.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.