使用ASP.NET MVC实现Spark全球化

4

我正在使用Spark ViewEngine、ASP.NET MVC和.resx文件。

我想通过我的自定义SessionModel (Session) 设置一种语言,该模型是通过Castle.Windsor进行注册,并具有可由用户设置的Culture字符串属性...

我需要当前语言在每个视图中保持不变,而无需不断地设置当前UICulture。

每次都不需要在每个控制器操作中执行以下操作:

    public SessionModel SessionModel { get; set; }

    public ActionResult Index()
    {
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(SessionModel.Culture);
        Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
    }

这种做法的问题在于,如果我进入另一个页面,当前语言环境就会恢复为默认语言。
在Spark视图中,我只需调用以下代码即可获取当前语言环境:
${SR.Home}

SR.resx包含一个名为Home的公共条目。

有没有好的想法来完成这个任务,我应该使用ActionFilter吗?


可能是如何本地化ASP.NET MVC + Spark应用程序?的重复问题。 - bzlm
他所谈论的示例正是存在问题的,它将信息持久化到一个普通的ASP.NET Session中,并且必须在每个附加的控制器上请求该信息。 - Andrew
3个回答

1

动作过滤器似乎是个好主意:

public class SetCultureActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        CultureInfo culture = FetchCultureFromContext(filterContext);
        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = culture;
        base.OnActionExecuting(filterContext);
    }

    private CultureInfo FetchCultureFromContext(ActionExecutingContext filterContext)
    {
        throw new NotImplementedException();
    }
}

然后使用这个属性装饰你的基础控制器。


我一直在尝试类似的东西,但问题是我无法将我注入到IActionFilter中的Windsor Session。这就带来了一个问题,如何保持我的语言当前...现在我唯一能做的就是使用HTTPContext.Currrent.Session,这真的很烦人。然而,也许我看错了,你对FetchCultureFromContext有什么想法? - Andrew
是的,你不能直接使用 DI。有一些解决方法。不过,在 ASP.NET MVC 3 中,这将成为可能。 - Darin Dimitrov
我最终使用了这个链接:http://weblogs.asp.net/psteele/archive/2009/11/04/using-windsor-to-inject-dependencies-into-asp-net-mvc-actionfilters.aspx 将我的会话注入到自定义的ActionFilterAttribute中,它起作用了。感谢您的帮助。 - Andrew

0

针对这个问题,如果您正在使用Spark View Engine,则有一个更好的、可扩展的解决方案(从灵活性角度考虑)。

请查看代码库中的示例解决方案,了解如何使用Spark进行国际化或全球化的优秀示例。绝对不需要开始在ActionFilters中使用花哨的东西-如果这是您未来的计划,这种方法适用于MVC2和MVC3,可以实现轻松迁移。

更新

针对您关于Spark代码库中示例的其他问题,我认为有几种方法可以解决这个问题。其中一种方法是将文化作为会话的一部分保留下来,但在过去的项目中,我们不想这样做,我们像许多网站一样,通过确保将它包含在URL中的路由数据参数中包含文化信息:

routes.Add(new Route("{culture}/{controller}/{action}/{id}", new MvcRouteHandler())
   {
      Defaults = new RouteValueDictionary(
         new { culture="en-us" action="Index", id="" }),
   });

这种东西与我上面提到的Spark模块结合使用,使您可以将时间专注于.resx文件,而不是手动 figuring out culture 和 routing。

您在同一视图文件夹中有一个Index.spark和一个Index.fr.spark意味着其余问题已为您解决。

希望能帮到您!
祝一切顺利
Rob


请查看下面的回复,内容太多无法适应这个小框框。 - Andrew

0
我想我漏掉了什么。这就是我试图避免的(Application.cs)在Spark示例中,我已经有一个自定义会话,它不需要管理另一个会话,只是为了“文化”:
示例代码:
    public static string GetSessionCulture(ControllerContext controllerContext)
    {
        return Convert.ToString(controllerContext.HttpContext.Session["culture"]);
    }

    public static void SetSessionCulture(ControllerContext controllerContext, string culture)
    {
        controllerContext.HttpContext.Session["culture"] = culture;
    }

完成后,我如何为每个页面加载当前区域设置?我需要在HomeController Index内部进行调用,从会话中获取当前区域设置:

    public object Index()
    {
        var user = new UserInfo
                               {
                                   Name = "Frankie",
                                   Culture = Application.GetSessionCulture(ControllerContext)
                               };

        try
        {
            Thread.CurrentThread.CurrentCulture = 
                CultureInfo.CreateSpecificCulture(user.Culture);
        }
        catch
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");
        }
        Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

        ViewData["user"] = user;
        return View();
    }

目前我能想到的唯一方法是创建自定义ActionFilter或创建基础控制器。


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