I am using the following article Addition to ASP.NET MVC Localization - Using routing to support multi-culture routes.
If you look at section "Registering routes" you will see that current routes are updated (in the "RegisterRoutes" method) with the "{culture}" segment.
The difference is that I want to keep the current routes and add a duplicate for each one with a "{culture}" segment, so for a route like "foo/bar" I would get a duplicate "{culture}/foo/bar".
You can see I'm also making sure the new route comes first .
public static void MapMvcMultiCultureAttributes(this RouteCollection routes, bool inheritedRoutes = true, string defaultCulture = "en-US", string cultureCookieName = "culture")
{
routes.MapMvcAttributeRoutes(inheritedRoutes ? new InheritedRoutesProvider() : null);
var multiCultureRouteHandler = new MultiCultureMvcRouteHandler(defaultCulture, cultureCookieName);
var initialList = routes.ToList();
routes.Clear();
foreach (var routeBase in initialList)
{
var route = routeBase as Route;
if (route != null)
{
if (route.Url.StartsWith("{culture}"))
{
continue;
}
var cultureUrl = "{culture}";
if (!String.IsNullOrWhiteSpace(route.Url))
{
cultureUrl += "/" + route.Url;
}
var cultureRoute = routes.MapRoute(null, cultureUrl, null, new
{
culture = "^\\D{2,3}(-\\D{2,3})?$"
});
cultureRoute.Defaults = route.Defaults;
cultureRoute.DataTokens = route.DataTokens;
foreach (var constraint in route.Constraints)
{
cultureRoute.Constraints.Add(constraint.Key, constraint.Value);
}
cultureRoute.RouteHandler = multiCultureRouteHandler;
route.RouteHandler = multiCultureRouteHandler;
}
routes.Add(routeBase);
}
}
The "InheritedRoutesProvider" looks like this:
private class InheritedRoutesProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(ActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes(typeof(IDirectRouteFactory), true)
.Cast<IDirectRouteFactory>()
.ToArray();
}
}
My controller looks like this:
public class MyBaseController: Controller
{
[HttpGet]
[Route("bar")]
public virtual ActionResult MyAction(){
{
return Content("Hello stranger!");
}
}
[RoutePrefix("foo")]
public class MyController: MyBaseController
{
}
My "RegisterRoutes" method looks like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcMultiCultureAttributes();
routes.LowercaseUrls = true;
}
Now, if I do:
Adding an Action to a Controller You add a new action to a controller by adding a new method to the controller. For example, the controller in Listing 1 contains an action named Index() and an action named SayHello(). Both methods are exposed as actions.
So, every public method inside the Controller is an action method in MVC. Action Method can not be a private or protected method. If you provide the private or protected access modifier to the action method, it will provide the error to the user, i.e., “resource can not be found” as below.
All the public methods in the Controller class are called Action methods. The Action method has the following restrictions. - Action method must be public. It cannot be private or protected.
The one restriction on action method is that they have to be instance method, so they cannot be static methods. Also there is no return value restrictions. So you can return the string, integer, etc.
I can give you an example of how I would do it. That example you are using is quite old.
Implement in your controllers (use inheritance) the BeginExecuteCore method as below:
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
string cultureName = RouteData.Values["culture"] as string;
if (cultureName == null)
cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ?
Request.UserLanguages[0] : // obtain it from HTTP header AcceptLanguages
null;
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
if (RouteData.Values["culture"] as string != cultureName)
{
// Force a valid culture in the URL
RouteData.Values["culture"] = cultureName.ToLower(); // lower case too
// Redirect user
Response.RedirectToRoute(RouteData.Values);
}
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
return base.BeginExecuteCore(callback, state);
}
Add some routes
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Custom",
url: "{controller}/{action}/{culture}",
defaults: new { culture = CultureHelper.GetDefaultCulture(), controller = "Coordinate", action = "Index" }
Implement a culture helper class
public static class CultureHelper { private static readonly List _cultures = new List { "listOfClutures" };
public static bool IsRighToLeft()
{
return System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.IsRightToLeft;
}
public static string GetImplementedCulture(string name)
{
if (string.IsNullOrEmpty(name))
return GetDefaultCulture(); // return Default culture
if (!CultureInfo.GetCultures(CultureTypes.SpecificCultures).Any(c => c.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)))
return GetDefaultCulture(); // return Default culture if it is invalid
if (_cultures.Any(c => c.Equals(name, StringComparison.InvariantCultureIgnoreCase)))
return name; // accept it
var n = GetNeutralCulture(name);
foreach (var c in _cultures)
if (c.StartsWith(n))
return c;
return GetDefaultCulture(); // return Default culture as no match found
}
public static string GetDefaultCulture()
{
return "en-GB"; // return Default culture, en-GB
}
public static string GetCurrentCulture()
{
return Thread.CurrentThread.CurrentCulture.Name;
}
public static string GetCurrentNeutralCulture()
{
return GetNeutralCulture(Thread.CurrentThread.CurrentCulture.Name);
}
public static string GetNeutralCulture(string name)
{
if (!name.Contains("-")) return name;
return name.Split('-')[0]; // Read first part only. E.g. "en", "es"
}
public static List<KeyValuePair<string, string>> GetImplementedLanguageNames()
{
List<KeyValuePair<string, string>> languageNames = new List<KeyValuePair<string, string>>();
foreach (string culture in _cultures)
{
languageNames.Add(new KeyValuePair<string, string>(culture, CultureInfo.GetCultureInfo(culture).EnglishName));
}
languageNames.Sort((firstPair, nextPair) =>
{
return firstPair.Value.CompareTo(nextPair.Value);
});
string currCulture = GetCurrentCulture();
languageNames.Remove(new KeyValuePair<string, string>(currCulture, CultureInfo.GetCultureInfo(currCulture).EnglishName));
languageNames.Insert(0, new KeyValuePair<string, string>(currCulture, CultureInfo.GetCultureInfo(currCulture).EnglishName));
return languageNames;
}
public static string GetDateTimeUsingCurrentCulture(DateTime dateToConvert)
{
CultureInfo ci = new CultureInfo(GetCurrentCulture());
return dateToConvert.ToString(ci.DateTimeFormat.ShortDatePattern + ' ' + ci.DateTimeFormat.ShortTimePattern);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With