I am developing an online store using ASP.NET Core 2 and I am struggling with how to implement route localization, ex. depending from the country where user is from I want him to see /en/products or /pl/produkty.
I managed to implement culture as part of the url, like /en/...., and user can also change default language by clicking a button on the website. However, I have no idea how to localize whole urls. I don't want to put hundreds of urls in Startup.cs (MapRoute). I need a better solution, which is working automatically behind the scenes.
If someone change directly the url (ex. en/products) and put pl instead of en, I want him/her to be redirected to pl/produkty automatically.
I hope you can help me!
here's a very good ressource here:
Asp.Net core Localization deep dive
Precisely here's what you're looking for:
IList<CultureInfo> supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-US"),
new CultureInfo("fi-FI"),
};
var localizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
var requestProvider = new RouteDataRequestCultureProvider();
localizationOptions.RequestCultureProviders.Insert(0, requestProvider);
app.UseRouter(routes =>
{
routes.MapMiddlewareRoute("{culture=en-US}/{*mvcRoute}", subApp =>
{
subApp.UseRequestLocalization(localizationOptions);
subApp.UseMvc(mvcRoutes =>
{
mvcRoutes.MapRoute(
name: "default",
template: "{culture=en-US}/{controller=Home}/{action=Index}/{id?}");
});
});
});
Related
I created my first app with ASP.NET Core. When I debug it, I see a problem with words that have accents:
How can I correctly localize the application?
Update:
I tried to implement Joe's suggestion, but I didn't get the expected result as you can see in this image.
The strings displayed from the database are okay, but the strings used in the view template like title or text are displayed incorrectly.
I don't want a multi-language application, just one in português.
On the old asp.net this configurations was done on .config with element
text html
in project.json you need this dependency
"Microsoft.Extensions.Localization": "1.0.0-rc2-final",
in Startup.cs in ConfigureServices you need code like this:
services.AddLocalization(options => options.ResourcesPath = "GlobalResources");
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("en"),
new CultureInfo("fr-FR"),
new CultureInfo("fr"),
};
// State what the default culture for your application is. This will be used if no specific culture
// can be determined for a given request.
options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
// You must explicitly state which cultures your application supports.
// These are the cultures the app supports for formatting numbers, dates, etc.
options.SupportedCultures = supportedCultures;
// These are the cultures the app supports for UI strings, i.e. we have localized resources for.
options.SupportedUICultures = supportedCultures;
// You can change which providers are configured to determine the culture for requests, or even add a custom
// provider with your own logic. The providers will be asked in order to provide a culture for each request,
// and the first to provide a non-null result that is in the configured supported cultures list will be used.
// By default, the following built-in providers are configured:
// - QueryStringRequestCultureProvider, sets culture via "culture" and "ui-culture" query string values, useful for testing
// - CookieRequestCultureProvider, sets culture via "ASPNET_CULTURE" cookie
// - AcceptLanguageHeaderRequestCultureProvider, sets culture via the "Accept-Language" request header
//options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
//{
// // My custom request culture logic
// return new ProviderCultureResult("en");
//}));
});
in Configure you need code something like this:
var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);
I have some working demo code here, if you need more
I used IdentityServer3.Contrib.Localization to provide translation to the identityserver.
IdentityServer3.Contrib.Localization provides only localization for scopes, messages, events but still there are missing texts to translate in login page and etc.
I think you should provide a custom views for every language using IViewService but i don't know if this is the correct path.
For example in order to provide a localization for a specific language i register this in startup class configuration:
// Register the localization service
idServerServiceFactory.Register(
new Registration<ILocalizationService>(r => new GlobalizedLocalizationService(
new LocaleOptions { Locale = "de-DE" })));
but now i want to change the language based on the language that user input or based on the browser accept-language, how can i change the localization for (scopes, events, messages, views) in run time.
some one mention that i can use OwinEnvironementService and inject it to the localization service to get the language but is there any example?
Also i think that i can provide an owin middleware in order to provide the needed change in localization based on the language but any suggestions?
The IdentityServer3.Localization(nuget.org) package can now do this:
var opts = new LocaleOptions
{
LocaleProvider = env =>
{
var owinContext = new OwinContext(env);
var owinRequest = owinContext.Request;
var headers = owinRequest.Headers;
var accept_language_header = headers["accept-language"].ToString();
var languages = accept_language_header
.Split(',')
.Select(StringWithQualityHeaderValue.Parse)
.OrderByDescending(s => s.Quality.GetValueOrDefault(1));
var locale = languages.First().Value;
return locale;
}
};
var factory = new IdentityServerServiceFactory();
factory.Register(new Registration<LocaleOptions>(opts));
factory.LocalizationService = new Registration<ILocalizationService, GlobalizedLocalizationService>();
=> Link to sample here.
I have a Dynamic Data site in a folder called admin. This folder is in the root of the website and referenced in the reserved paths section of the web.config file.
After upgrading from Umbraco 4.7.2 to 6.0.5 I've noticed that the links in the Dynamic Data site that normally take me to my tables are now trying to hit the /umbraco/rendermvc/List controller and action. I'm assuming that somehow my routes have been changed, but being so new to MVC I have no idea how to restore these.
If it is any help, this is the section of my startup code that used to register the contexts correctly. Any help on how to restore these routes without breaking the routing of the new Umbraco version would be very appreciated!
public static void RegisterContext(RouteCollection routes, string dbName, Type contextType, string ddFolder)
{
var model = new MetaModel
{
DynamicDataFolderVirtualPath = ddFolder,
FieldTemplateFactory =
new FieldTemplateFactory()
{TemplateFolderVirtualPath = "~/admin/DynamicData/FieldTemplates",}
};
model.RegisterContext(contextType, new ContextConfiguration() {ScaffoldAllTables = true});
routes.Add(new DynamicDataRoute("admin/{dbname}/{table}/{action}.aspx")
{
Constraints = new RouteValueDictionary(new
{
action = "List|Details|Edit|Insert",
dbname = dbName
}),
Model = model
});
Models[dbName] = model;
}
I think you have to put your custom stuff in an override on the OnApplicationStarted event in a custom global.asax which inherits from Umbraco.Web.UmbracoApplication (I haven't tried it yet), see this blog (about half way down the page) and our.umbraco.
I've been struggling with this for a couple of days now. Can't find any good example, or an example that I understand.
Background:
I own a small blog platform for user to blog.
Each user gets their own subdomain and for now there is no sitemap available. Not good.
I want to create some kind of dynamic sitemap, where all sitemapnodes is retreived from the database. The sitemap will be used only for the search engine spiders.
System: ASP.NET, mySQL.
The sitemap is pure XML. So I need in some way to create an ASPX file that return xml-data instead of html.
And I need to somehow redirect the web.sitemap to that dynamic file.
I have never worked with XML, and I dont know how to create a file that creates XML data. So i dont even know what to search for.
I don't want any static sitemap file to be stored on the server. Everything should be created on the fly.
So. Please. If you can give me some advise about XML, any example on the internet, or just what to search for.
My main questions:
1.
How to create XML output from aspx file?
2.
How do I "inform" the system, and search engine crawlers that the file to crawl is "/sitemap.aspx"
ThankS!
I looked into MvcSiteMapProvider.MVC5 and I could not get it to work. First of all it modified my Web.config to the point that my css and js files were getting a 404 not found when running my web app.
With the time I spent getting MvcSiteMapProvider to work I could have just wrote my own.
So... here is my own dumbed down version of generating a sitemap xml.
The only thing is you have to specify your routes manually. I haven't added reflection yet to go through each controller and pull out each action.
The data-driven piece works very well though.
In your Home controller add the action Sitemap and the private helper methods.
GetRouteUrls is the manually added controller/action routes.
GetDynamicUrls builds the data-driven Urls. In my example I have a LiquidsController and a Details(string id) action.
public ActionResult Sitemap()
{
var xml = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("urlset",
new XAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")
, GetRouteUrls()
, GetDynamicUrls()
)
);
return new XmlActionResult(xml);
}
private List<XElement> GetDynamicUrls()
{
var result = new List<XElement>();
using (var db = new ApplicationDbContext())
{
var liquids = db.Liquids.ToList();
foreach (var liquid in liquids)
{
result.Add(LocUrl("Liquids", "Details", liquid.FriendlyId));
}
}
return result;
}
private List<XElement> GetRouteUrls()
{
var result = new List<XElement>();
result.Add(LocUrl("Account", "Register"));
result.Add(LocUrl("Account", "Login"));
result.Add(LocUrl("Home", "Index"));
result.Add(LocUrl("Home", "About"));
result.Add(LocUrl("Home", "Contact"));
result.Add(LocUrl("Home", "TermsOfService"));
result.Add(LocUrl("Home", "PrivacyStatement"));
result.Add(LocUrl("Liquids", "Index"));
result.Add(LocUrl("Vendors", "Index"));
result.Add(LocUrl("Hardware", "Index"));
return result;
}
private XElement LocUrl(string controller, string action, string id = null)
{
if (!string.IsNullOrEmpty(id))
action = string.Format("{0}/{1}", action, id);
var baseUri = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
return new XElement("url",
new XElement("loc", string.Format("{0}{1}/{2}", baseUri, controller, action))
);
}
I then added a route so I could access the sitemap doing /sitemap
routes.MapRoute(name: "sitemap", url: "sitemap", defaults: new {controller = "Home", action = "Sitemap"});
The XmlActionResult return type can be found here:
Return XML from a controller's action in as an ActionResult?
I would like to have users insert and edit information about entities on the same page in a similar fashion to google alerts: http://www.google.com/alerts/manage
Any advice on how this could be achieved?
It is possible changing the routing in the method RegisterRoutes in Global.asax as indicated in the remarks section present in the same file.
Enabling this section:
routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") {
Action = PageAction.List,
ViewName = "ListDetails",
Model = DefaultModel
});
instead of the already enabled:
routes.Add(new DynamicDataRoute("{table}/{action}.aspx")
{
Constraints = new RouteValueDictionary(new { action = List|Details|Edit|Insert" }), Model = DefaultModel
});
It's also possible to enable custom routes for particular tables.