5

With the example URL:

www.domain.com/contact-us

Which renders in English. There are a set of other languages this website supports:

www.domain.com/es/contact-us
www.domain.com/jp/contact-us  
www.domain.com/de/contact-us
www.domain.com/pt/contact-us

Here is the re-write rule for English (default language)

<rewrite url="^/contact-us(\?(.+))?$" to="~/Pages/Contact.aspx$1" processing="stop"/>

How would I modify this/add a new rule to re-write:

www.domain.com/jp/contact-us  

To:

~/Pages/Contact.aspx?language=jp

Preferably without having to write a new rule, for every language for every content page!

To complicate things, it needs to match IETF language tags. These are varied enough that it looks like a regex to match them would be a difficult route: https://en.wikipedia.org/wiki/IETF_language_tag

Ideally I need to get the list of languages from the database, and match the language tag field on the fly. But I'm not sure how to do this as I've only ever written static rules.

9
  • Since you need to connect to a database, couldn't you write your own HTTP module (based on the HttpContext.RewritePath method)? Commented Aug 19, 2015 at 6:56
  • @SimonMourier any good tutorials you can link me to showing me how to do this? I've had a look but find it all a bit confusing! Commented Aug 19, 2015 at 11:17
  • @SimonMourier I've actually gotten a module to work up to the stage where when you give it the url /de/contact-us it gives /contact-us?lang=de but RewritePath needs a physical path which means it looks like I should write all my url rewrite rules in this module? Commented Aug 19, 2015 at 11:41
  • @SimonMourier sorry for all the comments, but is this: pastebin.com/HntCsbdF along the right lines? Commented Aug 19, 2015 at 11:54
  • Yes, that's exactly the idea. Few comments: for robustness, you want to test it in various environment (iis, iisexpress? with standard apps and lots of custom modules loaded, like MVC, see if your code doesn't mess up with other extensions, etc.). Also the check for static files is a bit naïve :-), but maybe sufficient for your context. Note: you can use Server.MapPath to get physical paths from urls. Commented Aug 19, 2015 at 12:38

2 Answers 2

3

Solved this by writing my own URL rewrite module. Sample code for anyone who runs into similar problems is below. Decided to dump all other URL rewriting and route everything through this module instead.

Don't think this is easily possible with static rules.

public class DynamicURLRewrite : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest);
    }

    public void Dispose()
    {
        throw new NotImplementedException();
    }

    void context_AuthorizeRequest(object sender, EventArgs e)
    {
        var rw = new Rewriter();
        rw.Process();
    }
}

public class Rewriter
{
    public void Process()
    {
        using (MiniProfiler.Current.Step("Rewriter process"))
        {
            var context = HttpContext.Current;

            var rawURL = context.Request.RawUrl;
            var querystring = String.Empty;
            var urlParts = rawURL.Split('?');
            var url = urlParts[0];
            if (urlParts.Count() == 2) querystring = urlParts[1];
            if (url.StartsWith("/")) url = url.Substring(1);

            // Get language component
            Translation.Language inLanguage = null;
            {
                foreach (var lang in Translation.Language.GetAllLanguages())
                {
                    if (url.StartsWith(lang.LanguageTag, StringComparison.CurrentCultureIgnoreCase))
                    {
                        inLanguage = lang;
                        url = url.Substring(lang.LanguageTag.Length);
                        if (url.StartsWith("/")) url = url.Substring(1);
                        break;
                    }
                }
                if (inLanguage == null)
                {
                    inLanguage =
                        Translation.Language.GetLanguage(
                            Settings.Translation.ProjectReferenceVersionRequiredLanguageTag);
                }
            }

            // Querystring
            {
                if (!String.IsNullOrEmpty(querystring)) querystring += "&";
                querystring += "lang=" + inLanguage.LanguageTag.ToLower();
                querystring = "?" + querystring;
            }

            // Root pages
            {
                if (String.IsNullOrEmpty(url))
                {
                    context.RewritePath("~/pages/default.aspx" + querystring);
                    return;
                }
                if (url.Equals("login"))
                {
                    context.RewritePath("~/pages/login.aspx" + querystring);
                    return;
                }

And then some more complex rules:

            // Handlers
            if (url.StartsWith("handlers/"))
            {
                // Translation serving
                if(url.StartsWith("handlers/translations/"))
                {
                    var regex = new Regex("handlers/translations/([A-Za-z0-9-]+)/([A-Za-z0-9-]+).json", RegexOptions.IgnoreCase);
                    var match = regex.Match(url);
                    if (match.Success)
                    {
                        context.RewritePath("~/handlers/translation/getprojecttranslation.ashx" + querystring + "&project=" + match.Groups[1] + "&language=" + match.Groups[2]);
                        return;
                    }
                }
            }
Sign up to request clarification or add additional context in comments.

Comments

1
+500

Do you have access to a .htaccess file in your home directory? If so, you can make an automatic rewrite rule by writing the following

Options +FollowSymLinks
RewriteEngine on
RewriteRule /(.*)/contact-us/ /Pages/Contact.aspx?language=$1
RewriteRule /contact-us/ /Pages/Contact.aspx?language=en

Let me explain:

After RewriteRule, the user-friendly URL is on the left, here /(.*)/contact-us/ where (.*) is where jp will take place. Then that jp is transposed on the real URL on the right, here /Pages/Contact.aspx?language=$1 to replace $1.

Input URL: http://www.example.com/jp/contact-us
Output URL: http://www.example.com/Pages/Contact.aspx?language=jp

For the second RewriteRule, as the URL http://www.example.com/contact-us/ does not match the first model, it will turn into http://www.example.com/Pages/Contact.aspx?language=en automatically.

Please remember that the .htaccess file MUST be in the root directory (alongside Pages folder). Otherwise you will not get the desired result.

2 Comments

Giving you the bounty, I think having two rules /contact-us/ /Pages/Contact.aspx?language=en and /(.*)/contact-us/ /Pages/Contact.aspx?language=$1 is a clever solution
You can also do /(.*)/(.*)/ /Pages/$2.aspx?language=$1 to programmatically bind new pages.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.