Developing a multilingual website, besides localization of the page’s content it also makes sense to localize the URLs. In my first post dealing with localization I explained my basic approach how to localize pages using a derived MvcRouteHandler and a subtype of Route. In this post I am going to show a possibility to localize URLs by using routes and constraints.

What I want

1) I am going to have a search on my new site. I want this search page to have nice localized URLs for the different languages. The term “search” of the URL should be translated to each supported language.

Examples:

USA mysite.com/en-US/Search
Great Britain mysite.com/en-GB/Search
Germany mysite.com/de-DE/Suche
Switzerland mysite.com/de-CH/Suche
Italy mysite.com/it-IT/Ricerca

2) Furthermore I want to have URLs with the same ending for different languages. This ist usefull for URLs, which do not have to be translated.

USA mysite.com/en-US/FAQ
Great Britain mysite.com/en-GB/FAQ
Germany mysite.com/de-DE/FAQ
Switzerland mysite.com/de-CH/FAQ
Italy mysite.com/it-IT/FAQ

Approach

1) This can be done by registering different routes and using custom constraints. I did it like this:

public static void RegisterRoutes(RouteCollection routes)  
{  
    LanguageConstraint enLanguageConstraint = new LanguageConstraint("en");  
    LanguageConstraint deLanguageConstraint = new LanguageConstraint("de");  
    
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
        
    routes.Add(  
        new MultiLingualRoute("FAQ",  
        new RouteValueDictionary(new { controller = "CMS", action = "Show", Id = 1 }),  
        new RouteValueDictionary(new { validCountry = new CulturesConstraint() }),  
        new MvcApplication1.MultiLingualMvcRouteHandler())  
    );  
    
    routes.Add(  
        new MultiLingualRoute("Suche",  
        new RouteValueDictionary(new { controller = "Search", action = "AdvancedSearch" }),                  
        new RouteValueDictionary(new { validLanguage = deLanguageConstraint }),  
        new MvcApplication1.MultiLingualMvcRouteHandler())  
    );  
    
    routes.Add(  
        new MultiLingualRoute("Search",  
        new RouteValueDictionary(new { controller = "Search", action = "AdvancedSearch" }),  
        new RouteValueDictionary(new { validLanguage = enLanguageConstraint }),  
        new MvcApplication1.MultiLingualMvcRouteHandler())  
    );  
        
    routes.MapRoute(  
        "Default",                                              // Route name  
        "{controller}/{action}/{id}",                           // URL with parameters  
        new { controller = "Home", action = "Index", id = "" }  // Parameter defaults  
    );              
    
    foreach (Route r in routes)  
    {  
        if (r.GetType() == typeof(MultiLingualRoute))  
        {  
            r.Url = "{culture}/" + r.Url;  
            r.Defaults.Add("culture", "en-US");                      
        }  
    }  
}

At the first lines two LanguageConstraints are created. These constraints make sure, that this route is only used, if the given language is used.

public class LanguageConstraint : IRouteConstraint  
{  
    string Language { set; get; }  
    
    /// <summary>  
    /// Creates a new lanugage constraint  
    /// </summary>  
    /// <param name="Language">Allowed lanuage</param>  
    public LanguageConstraint(string language)  
    {  
        Language = language;  
    }  
    
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)  
    {  
        String CultureFromRoute = values["culture"].ToString();  
    
        try  
        {  
            if (CultureFromRoute.Length > 2 &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; CultureFromRoute.StartsWith(Language))  
            {  
                //validate, that the given culture from routeData is a valid culture  
                System.Globalization.CultureInfo.GetCultureInfo(CultureFromRoute);  
                return true;  
            }  
    
        }  
        catch (Exception) { }  
        return false;              
    }  
}

2) For those URLs with the same ending I crated a CulturesConstraint. This makes sure, that the page is only showed for given cultures

public class CulturesConstraint : IRouteConstraint  
{  
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)  
    {  
        List<String> CultureListe = new List<String>();  
        CultureListe.Add("en-GB");  
        CultureListe.Add("en-US");  
        CultureListe.Add("de-DE");  
        CultureListe.Add("it-IT");  
        return CultureListe.Contains(values["culture"].ToString());  
    }  
}

Feel free to drop me a line!