Hi,
I try to do my first own website in mvc3.
I read a lot of article about multilanguage website and tried different approach without real success.
My last tactic is : to pass the culture info in url and use routemanager to set the good culture:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Home",
id = UrlParameter.Optional }
);
foreach (Route r in routes)
{
if (!(r.RouteHandler is SingleCultureMvcRouteHandler))
{
r.RouteHandler = new MultiCultureMvcRouteHandler();
r.Url = "{culture}/" + r.Url;
if (r.Defaults == null)
{
r.Defaults = new RouteValueDictionary();
}
r.Defaults.Add("culture", CultureEnum.en);
if (r.Constraints == null)
{
r.Constraints = new RouteValueDictionary();
}
r.Constraints.Add("culture",
new CultureConstraint(CultureEnum.en, CultureEnum.fr));
}
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
#region Localisation Class
public class SingleCultureMvcRouteHandler : MvcRouteHandler { }
public class MultiCultureMvcRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(
RequestContext requestContext)
{
var culture = requestContext.RouteData.Values["culture"].ToString();
var ci = new CultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture(ci.Name);
return base.GetHttpHandler(requestContext);
}
}
public class CultureConstraint : IRouteConstraint
{
private string[] _values;
public CultureConstraint(params string[] values)
{
this._values = values;
}
public bool Match(HttpContextBase httpContext,
Route route, string parameterName,
RouteValueDictionary values, RouteDirection routeDirection)
{
string value = values[parameterName].ToString();
return _values.Contains(value);
}
}
public class CultureEnum
{
public static string fr = "fr-FR";
public static string en = "en-US";
}
#endregion
The routemanager work well. All time I switch the language, I saw the url change. The Thread.CurrentThread.CurrentUICulture and Thread.CurrentThread.CurrentCulture are set propertly. But:
- All time in page, it's the default language (neutral resx) who is displayed.
- If change my language again, I saw CurrentUICulture and CurrentCulture have my user language (fr) yet but still display the neutral default.
I try to put my 3 resx files (toto.resx, toto.fr-FR.resx, toto.en-US.resx)in multiple locations (global, local, myproject.Resources, etc...) nothing change.
It's all time the Default resx displayed.
I try to change the resourcesgenerator as ResXFileCodeGenerator, PublicResXFileCodeGenerator, etc... but same results.
The only trick, I found after one long and hard day is:
public static void SetCulture(CultureInfo newCulture)
{
if (newCulture == null)
return;
var classLi = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && t.Namespace == ResourcesNamespace
select t;
foreach (Type t in classLi)
{
PropertyInfo pi = t.GetProperty("Culture");
if (pi != null)
{
pi.SetValue(t, newCulture, null);
}
}
}
}
It's ugly but it works. But I a afraid this solution will fail with multiple users.
So ladies and gentlemen if you have the kindness to share your ideas :)