ASP.net中的URL重写支持多语言功能

5

使用示例 URL:

www.domain.com/contact-us

这段文字是用英语书写的。该网站还支持其他语言:

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

这是英语(默认语言)的重写规则。
<rewrite url="^/contact-us(\?(.+))?$" to="~/Pages/Contact.aspx$1" processing="stop"/>

我该如何修改/添加一个重写规则:

www.domain.com/jp/contact-us  

To:

~/Pages/Contact.aspx?language=jp

最好不用为每个语言的每个内容页面编写新规则!
复杂的是,它需要匹配IETF语言标签。这些标签的差异足够大,看起来使用正则表达式进行匹配将是一条困难的路线: https://en.wikipedia.org/wiki/IETF_language_tag 理想情况下,我需要从数据库中获取语言列表,并即时匹配语言标签字段。但是我不确定如何做到这一点,因为我只编写过静态规则。

既然你需要连接数据库,为什么不编写自己的HTTP模块(基于HttpContext.RewritePath方法)呢? - Simon Mourier
@SimonMourier,你能给我提供一些好的教程链接吗?我已经找过了,但是发现它们都有点令人困惑! - Tom Gullen
@SimonMourier,对于所有的评论感到抱歉,但是这个:http://pastebin.com/HntCsbdF 是否正确? - Tom Gullen
是的,这正是我们的想法。几点建议:为了保证强健性,您需要在各种环境(iis、iisexpress?是否加载了标准应用程序和大量自定义模块,例如 MVC,看看您的代码是否与其他扩展不冲突等)中对其进行测试。此外,检查静态文件的方式有些天真 :-),但可能对您的上下文足够了。注意:您可以使用 Server.MapPath 从 URL 获取物理路径。 - Simon Mourier
@SimonMourier,我目前正在使用Inteligencia URL重写,这使得编写大部分规则变得容易。有没有办法在不必编写自己的自定义模块的情况下实现我想要的功能?如果必须这样做,我会的,但宁愿使用Inteligencia URL重写来完成大部分工作。 - Tom Gullen
显示剩余4条评论
2个回答

3
通过编写自己的URL重写模块解决了这个问题。以下是任何遇到类似问题的人的示例代码。决定放弃所有其他URL重写,并将所有内容都通过此模块路由。
我认为使用静态规则很难实现这一点。
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;
                }

然后是一些更复杂的规则:

            // 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;
                    }
                }
            }

1

您是否可以访问您的主目录中的 .htaccess 文件?如果是,您可以通过编写以下内容来创建自动重写规则:

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

让我来解释一下:
在使用了“RewriteRule”之后,友好的URL显示在左边,例如“/(.*)/contact-us/”,其中的“(.*)”是“jp”的位置。然后,“jp”会被替换成真实的URL,例如“/Pages/Contact.aspx?language=$1”,以取代“$1”。
输入URL:http://www.example.com/jp/contact-us
输出URL:http://www.example.com/Pages/Contact.aspx?language=jp 对于第二个“RewriteRule”,由于URL“http://www.example.com/contact-us/”与第一个模型不匹配,它会自动变成“http://www.example.com/Pages/Contact.aspx?language=en”。
请记住,“.htaccess”文件必须位于根目录中(与“Pages”文件夹并列)。否则,您将无法获得所需的结果。

我认为给你赏金的同时,拥有两个规则/contact-us/ /Pages/Contact.aspx?language=en/(.*)/contact-us/ /Pages/Contact.aspx?language=$1是一个聪明的解决方案。 - Tom Gullen
您还可以使用 /(.*)/(.*)/ /Pages/$2.aspx?language=$1 来编程绑定新页面。 - TheSola10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接