深入了解如何构建您的第一个多语言ASP。NET MVC 5 Web应用程序

下载demo - 3.9 MB

介绍

这篇文章解释了如何创建一个简单的多语言ASP。NET MVC 5 Web应用程序。该应用程序将能够处理英语(美国),西班牙语和法语。英语将是默认语言。当然,扩展解决方案以包含新语言是非常容易的。

首先,我们假设读者对ASP有基本的了解。NET MVC 5框架。其他相关技术,如jQuery 将在本文中稍加注释,因为它们已用于添加新功能。我将重点讲解MVC框架组件。无论如何,我将尝试解释每个组件是如何工作的,或者至少为您提供获得更详细信息的链接。本文的目的不是解释每种技术的每一行代码,也不是重复其他文章中有详细说明的说明。我的目标是解释演示应用程序的主要特性,同时记住关键问题,以便更好地理解和理解。

也就是说,我们的演示应用程序将有一个HomeController,它具有三个基本的典型操作,比如Index、About和Contact。此外,我们将从一个BaseController派生这个控制器,我们将在后面看到,为每个控制器提供通用功能。因此,在视图中渲染的名为from HomeController 将根据默认或用户选择的语言本地化。

背景

在我看来,当谈到多语言ASP。NET MVC应用程序,这将是必要的考虑至少以下关键问题:

考虑应用全球化和本地化的组件。为多语言目的配置URL路由,特别是考虑到SEO的观点。就此而言,最重要的问题是在不同的URL上保持不同的内容,不要在同一个URL上提供不同的内容。

全球化和地方化

我们必须能够为在控制器上运行的当前线程上处理的每个请求设置适当的区域性。因此,我们将创建一个CultureInfo对象,并在线程上设置CurrentCulture和CurrentUICulture属性(请参阅此处),以提供基于适当文化的内容。为此,我们将从Url路由中提取区域性信息。

属性引用全球化或管理日期、货币或数字的方式。相反,现代文化支配着本地化,或者内容和资源如何被翻译或本地化。在本文中,我将重点讨论本地化。

CultureInfo 类基于每个特定区域性的惟一名称实例化。这段代码使用模式“xx-XX”,其中前两个字母代表语言,第二个字母代表子语言、国家或地区(更多信息请参见这里)。在这个演示应用程序中,en-US、es-ES和fr-FR代码表示支持语言:英语(美国)、西班牙语(西班牙)和法语(法国)。

话虽如此,以下是要根据区域性进行本地化的元素列表:

纯文本。

我们将使用资源文件翻译文本。简而言之,这些文件允许我们根据键/值对字典来保存内容资源,主要是文本和图像。我们将使用这些文件来存储文本,而不是图像。
图像。

我们将通过扩展包含在System.Web.Mvc.dll程序集中的UrlHelper类来本地化图像。通过插入到这个类中的扩展方法,我们可以根据支持的语言在以前创建的文件夹结构中查找图像。简单解释一下,UrlHelper类包含在MVC应用程序中处理URL地址的方法。特别是,我们可以通过使用WebViewPage类的内置属性UrlHelper在Razor视图中获得对UrlHelper类的引用。点击这里查看更多信息。
来自客户端和服务器代码的验证消息。

为了翻译服务器端验证消息,我们将使用资源文件。为了翻译客户端验证消息,我们将覆盖默认消息。因为我们将使用jQuery验证插件1.11.1来应用客户端验证,所以我们必须覆盖来自这个插件的消息。本地化的消息将根据支持的语言保存在单独的文件中。因此,为了访问本地化的脚本文件,我们将再次扩展UrlHelper类。
根据应用程序的需求,可能需要本地化整个视图。所以,我们将考虑这个问题。

在本演示中,英语(美国)和西班牙语将不使用此选项,但出于演示目的,法语将使用此选项。因此,我们将从defaultrazorviewengine创建一个新的派生ViewEngine来实现这个g卵圆形。这个新的视图引擎将通过之前创建的文件夹树来查找视图。
其他Script  CSS 文件。

对于大型应用程序,可能有必要考虑本地化脚本和CSS文件。可以使用与映像文件相同的策略。我们不深入研究这个问题,只是加以考虑。
来自后端存储组件(如数据库)的本地化内容。

在这个演示应用程序中,我们将不使用数据库。这篇文章会太长。相反,我们假设,如果必要的话,线程上设置的当前区域性的信息将从数据访问层提供给数据库。这样,相应的翻译文本或本地化的图像将被返回。如果计划使用来自数据库的本地化内容,至少要记住这一点。

让我们看看一些关于我们的演示应用程序的截图:

首页英文(美国)版本:

家page 西班牙版本:

这是一个非常简单的应用程序,但足以深入了解多语言的关键问题。

主页视图页面包含本地化的文本和图像。关于视图页面只包括本地化的文本。联系人视图页面也包含本地化文本,但它还包含一个部分视图,该视图带有一个表单,用于发布数据并在相应的底层模型上应用客户端和服务器验证。共享错误视图页面也将被翻译。从布局视图页面中提供了选择标志的列表。

URL路由

首先,我们必须完成的事实,而不是服务于不同的基于语言的背后,内容得到相同的URL只配置appropiate  URL路由是强制性的提供基于语言内容按照不同的URL又是;因此,我们将配置路由从URL中提取特定的文化包括多语言支持的路由。

在调试模式下,我们的url地址看起来如下所示。我假设我们的演示应用程序在本地主机上使用XXXXX端口提供服务。

英语(美国)语言:

http://localhost:xxxx/en-us/homs/index/localhost:xxxxx / homs/indexhttp://localhost:xxxxx / homs/about/localhost:xxxxx / en-us/homs/about/localhost:xxxxx / homs/contact/index.localhost:xxxx/en-us/homs/contact/contact.localhost:xxxx/en-us/homs/contact.localhost:xxxxx / contact.localhost:xxxx/en-us/homs/contact.localhost:xxxx/en-us/homs/contact.localhost:xxxx/en-us/homs/contact
西班牙语:

http://localhost: XXXXX / es-ES / Home /索引http://localhost: XXXXX es-ES / Home / http://localhost: XXXXX es-ES / Home /接触
法语:

http://localhost: XXXXX / - fr / Home /索引http://localhost: XXXXX / - fr / Home / http://localhost: XXXXX / - fr / Home /接触

此外,我们将在布局视图页面中为用户提供支持语言的列表。因此,用户总是可以通过单击其中一种语言来获得所需的语言。当用户选择一种不同的语言时,我们会使用cookie保存这个手动选择。使用Cookie可能会引起争议。所以,使用与否由你决定。这不是文章的重点。我们将使用它,考虑到我们将永远不会创建cookie从服务器端基于内容的URL路由。所以,如果一个用户从来没有手动改变语言,他将导航在语言,他进入我们的网站。下次用户进入我们的网站时,如果cookie存在,他们将被重定向到合适的URL根据他们最后的语言选择。无论如何,请记住,永远不要只考虑使用cookie、会话状态、浏览器的客户端用户设置等来从同一个URL提供不同的内容。

使用的代码

创建多语言应用程序的第一步

我使用Microsoft Visual Studio 2013提供的简单的MVC 5模板开始工作,将身份验证选项改为无身份验证。正如您在下面看到的,我的演示应用程序的名称是MultiLanguageDemo。然后,我重新整理了文件夹,如下图所示:

注意内容目录下的文件夹。就个人而言,我喜欢用这种结构来存储图像、脚本、样式和文本。每次创建一个新目录并向其中添加类时,默认情况下会添加一个带有文件夹名称的新名称空间。把它考虑进去。我已经修改了web。配置到Views文件夹中,以包括这些新的名称空间。这样,您就可以从Razor view代码块中直接访问这些名称空间中的类。

由于en-US将是缺省文化,所以有必要配置web。配置按照:

我们将使用自定义GlobalHelper类来包含全局通用功能,比如读取线程上的当前区域性或web.config中的默认区域性。代码如下:

隐藏,复制Codepublic class GlobalHelper
{
public static string CurrentCulture
{
get
{
return Thread.CurrentThread.CurrentUICulture.Name;
}
}

public static string DefaultCulture
{
    get
    {
        Configuration config = WebConfigurationManager.OpenWebConfiguration("/");
        GlobalizationSection section = (GlobalizationSection)config.GetSection("system.web/globalization");
        return section.UICulture;
    }
}     

}

建立URL路由

我们有两种路径,LocalizedDefault和Default。我们将使用lang占位符来管理文化。这里是RouteConfig类在RouteConfig文件中的代码(更多关于URL路由):

隐藏,复制Code public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
       name: "LocalizedDefault",
       url: "{lang}/{controller}/{action}",
       defaults: new { controller = "Home", action = "Index"},
       constraints: new {lang="es-ES|fr-FR|en-US"}
   );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}",
        defaults: new { controller = "Home", action = "Index", lang = en-US }
    );
}

}

一方面,defaultroute 将用于匹配url而不指定显式区域性。因此,我们将对其进行配置,以使用默认区域性。注意在默认参数中lang是如何被设置为en-US culture的。

另一方面,LocalizedDefault路由被配置为在url上使用特定的区域性。此外,lang param被限制在支持语言es-ES、fr-FR 或en-US中。注意这是如何通过在MapRoute方法中设置constraints参数来配置的。这样我们就可以覆盖所有以前确定的路线。

配置控制器以提供适当的基于语言的内容

如前所述,切换区域性需要创建CultureInfo对象来设置处理发送给控制器的每个http请求的线程上的CurrentCulture和CurrentUICulture属性。使用MVC 5,可以通过多种方式实现这一点。在本例中,我将创建一个抽象的BaseController类,其余控制器将从该类派生。BaseController将包含通用的功能,并将覆盖System.Web.Mvc.Controller 类中的onactionexecute方法。关于onactionexecute方法的关键是要知道它总是在调用控制器方法之前被调用。

最后,简单地说,获得它的另一种方法是通过全局操作过滤器,而不是使用基类。在这个例子中没有考虑到它,但是如果您更喜欢的话,请记住它。

让我们来看看我们的BaseController类代码:

隐藏,收缩,复制Code public abstract class BaseController : Controller
{
private static string _cookieLangName = “LangForMultiLanguageDemo”;

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    string cultureOnCookie = GetCultureOnCookie(filterContext.HttpContext.Request);
    string cultureOnURL = filterContext.RouteData.Values.ContainsKey("lang") 
        ? filterContext.RouteData.Values["lang"].ToString() 
        : GlobalHelper.DefaultCulture;
    string culture = (cultureOnCookie == string.Empty) 
        ? (filterContext.RouteData.Values["lang"].ToString()) 
        : cultureOnCookie;
    
    if (cultureOnURL != culture)
    {
        filterContext.HttpContext.Response.RedirectToRoute("LocalizedDefault", 
        new { lang=culture,
                controller = filterContext.RouteData.Values["controller"],
                action = filterContext.RouteData.Values["action"]
        });
        return;
    }

    SetCurrentCultureOnThread(culture);

    if (culture != MultiLanguageViewEngine.CurrentCulture)
    {
        (ViewEngines.Engines[0] as MultiLanguageViewEngine).SetCurrentCulture(culture);
    }

    base.OnActionExecuting(filterContext);
}

private static void SetCurrentCultureOnThread(string lang)
{
    if (string.IsNullOrEmpty(lang))
        lang = GlobalHelper.DefaultCulture;
    var cultureInfo = new System.Globalization.CultureInfo(lang);
    System.Threading.Thread.CurrentThread.CurrentUICulture = cultureInfo;
    System.Threading.Thread.CurrentThread.CurrentCulture = cultureInfo;
}

public static String GetCultureOnCookie(HttpRequestBase request)
{
    var cookie = request.Cookies[_cookieLangName];
    string culture = string.Empty;
    if (cookie != null)
    {
        culture= cookie.Value;
    }
    return culture;
}

}

BaseController类覆盖onactionexecution方法。然后,我们从URL路由和cookie中获取关于特定区域性的信息。如果没有cookie,线程上的区域性将从Url路由设置。否则,如果最终用户手动选择了一种语言,然后cookie存在,http 响应将被重定向到相应的路由包含在cookie中存储的语言。

另外,要在线程上设置当前区域性,BaseController使用SetCurrentCultureOnThread私有函数。首先,根据作为参数传递的特定文化创建一个新的CultureInfo类。最后,使用先前创建的CultureInfo对象分配当前线程的CurrentUICulture和CurrentCulture属性。

处理纯文本

要翻译普通文本,我们将使用资源文件。这是存储要翻译的文本的好方法。存储基于键/值对字典,其中键是标识给定资源的字符串,值是翻译后的文本或本地化的图像。在内部,所有这些信息都以XML格式保存,并由Visual Studio Designer动态编译。

资源文件有一个resx扩展名。因此,在这个演示中,我们将为默认区域性创建三个不同的资源文件。一个是储存全球文本的。另一个是用于一般错误消息的RError.resx,最后一个是用于存储与主控制器相关的消息的RHome.resx。我喜欢在我的项目中创建这种资源文件结构,通常为每个控制器包含一个资源文件,但如果您喜欢。

对于其他支持的语言,我们将创建名称为rglobal .es .resx、rerror .es .resx、rpc .es .resx(西班牙语)和rnbsp . js .fr .resx、rerror .fr .resx和rpc .fr .resx(法语)的资源文件。请注意每个名称的文化代码。这是我们的资源文件树:

最重要的是要知道:

当您为默认区域性(如rglobal . resx&file)创建资源文件时,Visual Studio会自动生成一个名为rglobal的内部类。使用设计器时,您应该将访问修饰符更改为public以便在解决方案中使用它。让我们看看我们的英语和西班牙语的RGlobal文件:

每个特定区域性的资源在不同的程序集中编译,并根据区域性保存在不同的子目录中,并命名为assembly . Resources .dll。在我们的例子中,名称将是multilanguagedemo.resources .dll,一旦在线程上设置了特定区域性,运行时将相应地选择程序集。通过将资源文件名与关键字连接起来,控制器或其他类可以使用单个资源。instance  RGlobal。RGlobal。浏览器名称等。要使用Razor语法在视图中使用单独的资源,你只需要添加代码,比如@RHome。标题、@RHome。副标题或@RHome.Content。

处理图像

如前所述,我们将只在资源文件中存储文本,尽管图像也可能被保存。就我个人而言,我更喜欢用另一种方式保存图片。让我们看看我们的图像文件夹下的内容目录。

可以看到,已经为每个区域性创建了一个特定的文件夹。不需要本地化的图像将直接保存在Images文件夹中,如france . jpgor西班牙。jpg。这些文件只包含用于显示和选择语言的标志,因此不需要本地化。其余需要本地化的图像将单独存储。例如,en- usu子目录下的Welcome . jpgfile包含一个文本为“Welcome”的图片,而es- esu子目录下的Welcome . jpgfile包含一个文本为“Bienvenido”的图片。

说到这里,让我们继续使用UrlHelper类中的GetImage 方法扩展来选择本地化的图像。此静态方法将包含在扩展文件夹下名为UrlHelperExtensions. css的文件中的UrlHelperExtensions静态类中。代码如下:

隐藏,收缩,复制Codepublic static class UrlHelperExtensions
{
public static string GetImage(this UrlHelper helper,
string imageFileName,
bool localizable=true)
{
string strUrlPath, strFilePath = string.Empty;
if (localizable)
{
/* Look for current culture /
strUrlPath = string.Format("/Content/Images/{0}/{1}",
GlobalHelper.CurrentCulture,
imageFileName);
strFilePath = HttpContext.Current.Server.MapPath(strUrlPath);
if (!File.Exists(strFilePath))
{ /
Look for default culture */
strUrlPath = string.Format("/Content/{0}/Images/{1}",
GlobalHelper.DefaultCulture,
imageFileName);
}
return strUrlPath;
}

    strUrlPath = string.Format("/Content/Images/{0}", imageFileName);
    strFilePath = HttpContext.Current.Server.MapPath(strUrlPath);
    if (File.Exists(strFilePath))
    {   /* Look for resources in general folder as last option */
        return strUrlPath;
    }

    return strUrlPath;
}

}

我们将通过添加一个新的GetImage方法来扩展UrlHelper。该方法允许我们在images目录下查找本地化的图像。我们只需要通过传递正确的图像文件名来调用该方法。还有另一个布尔参数来设置图像是否本地化。如果是,方法将根据当前区域性在相应的子目录中查找结果,如果没有遇到,将尝试按该顺序使用默认区域性和通用文件夹。无论如何,如果一切配置良好,第一次搜索就足够了。

模板视图中的典型调用是:

隐藏,复制Code<img src="@Url.GetImage(“Welcome.jpg”)" alt="@RGlobal.Welcome"/>

是System.Web.Mvc.WebViewPage 类的一个属性,所有Razor视图都是从它派生的。此属性返回一个UrlHelper实例。这样,我们就可以访问我们的GetImage方法。

处理验证消息

我们将同时考虑服务器验证和客户端验证。为了将本地化应用到服务器端验证,我们将使用资源文件,而对于客户端验证,我们将创建类似于图像的目录结构。然后,我们将创建新的脚本文件来根据支持的语言覆盖默认的消息,并且我们将扩展urlhelperclass来访问这些新文件。

服务器验证

服务器验证通常在模型的控制器上执行。如果验证不正确,包含模型状态的模型状态字典对象ModelState将被设置为不正确。在代码中,这等于将ModelState的IsValid属性设置为false. 因此,ModelState字典将填满验证消息,根据输入字段、全局验证等,这些消息需要进行翻译。

在本例中,我将展示转换验证消息如何来自数据注释。在MVC项目中,通过使用包含在System.ComponentModel.DataAnnotations中的类来配置服务器验证是非常常见的。让我们看一个例子。

这是与应用于联系人视图的联系人模型相关的代码:

隐藏,收缩,复制Codenamespace MultiLanguageDemo.Models
{
[MetadataType(typeof(ContactModelMetaData))]
public partial class ContactModel
{
public string ContactName { get; set; }
public string ContactEmail { get; set; }
public string Message { get; set; }
}

public partial class ContactModelMetaData
{
    [Required(ErrorMessageResourceName = "RequiredField", 
    ErrorMessageResourceType = typeof(RGlobal))]
    [Display(Name = "ContactName", ResourceType = typeof(RHome))]
    public string ContactName { get; set; }

    [Required(ErrorMessageResourceName = "RequiredField", 
    ErrorMessageResourceType = typeof(RGlobal))]
    [Display(Name = "ContactEmail", ResourceType = typeof(RHome))]
    [DataType(DataType.EmailAddress)]
    public string ContactEmail { get; set; }

    [Required(ErrorMessageResourceName = "RequiredField", 
    ErrorMessageResourceType = typeof(RGlobal))]
    [Display(Name = "Message", ResourceType = typeof(RHome))]
    public string Message { get; set; }
}

}

一方面,我们有一个contactmodel类,它有三个简单的属性。另一方面,我们有一个contactmodelmetadata类,用于在contactmodel上应用验证,并设置进一步的功能或元数据,以便显示与字段、数据类型等相关的标签。

关于验证,我们正在根据需要配置所有的模型字段。因此,要实施本地化,必须引用与资源文件关联的自动生成的类。这是通过errormessageresourcetype属性完成的。我们还必须配置与我们想要显示的验证消息相关的关键字名称。这是通过使用ErrorMessageResourceName属性完成的。这样,来自资源文件的消息(根据区域性自动选择)将相应地返回。

客户端验证

通过使用客户端验证,可以在客户端执行验证,避免向控制器发出不必要的请求。我们将通过jQuery Validation Plugin 1.11.1和jQuery Validation unobtrusiveplugin来使用这个特性。当您使用Microsoft Visual Studio MVC 5模板项目启动一个新的MVC 5项目时,将自动生成对这些文件的引用。您可以在web中启用客户端验证。配置文件如下图所示:

你也可以通过继承类中的Html属性直接从视图中启用/禁用客户端验证。如下图所示,视图中的Html属性返回一个HtmlHelper对象,该对象包含EnableClientValidation和enableunobtrusivejavascriptmethods。一旦启用了客户端验证,htmlhelperclass就被允许自动编写客户端验证代码。

在我们的演示应用程序中,我们使用jQuery验证插件来执行验证。因此,默认消息是用英语显示的,但是我们需要为a提供翻译后的消息我支持的语言。为了实现这一点,我们将扩展插件。首先,我们将创建一个目录树,如下图所示。

然后,对于每种支持的语言,我们将创建一个javascript 文件,以根据当前线程上运行的区域性覆盖默认消息。以下是与西班牙语有关的守则:

隐藏,复制CodejQuery.extend(jQuery.validator.messages, {
  required: “Este campo es obligatorio.”,
  remote: “Por favor, rellena este campo.”,
  email: “Por favor, escribe una dirección de correo válida”,
  url: “Por favor, escribe una URL válida.”,
  date: “Por favor, escribe una fecha válida.”,
  dateISO: “Por favor, escribe una fecha (ISO) válida.”,
  number: “Por favor, escribe un número entero válido.”,
  digits: “Por favor, escribe sólo dígitos.”,
  creditcard: “Por favor, escribe un número de tarjeta válido.”,
  equalTo: “Por favor, escribe el mismo valor de nuevo.”,
  accept: “Por favor, escribe un valor con una extensión aceptada.”,
  maxlength: jQuery.validator.format(“Por favor, no escribas más de {0} caracteres.”),
  minlength: jQuery.validator.format(“Por favor, no escribas menos de {0} caracteres.”),
  rangelength: jQuery.validator.format(“Por favor, escribe un valor entre {0} y {1} caracteres.”),
  range: jQuery.validator.format(“Por favor, escribe un valor entre {0} y {1}.”),
  max: jQuery.validator.format(“Por favor, escribe un valor menor o igual a {0}.”),
  min: jQuery.validator.format(“Por favor, escribe un valor mayor o igual a {0}.”)
});

我想当然地认为jQuery和jQuery验证插件加载在这些文件之前。无论如何,为了从需要客户端验证的视图中引用这些文件,我们必须使用以下代码:

隐藏,复制Code@Scripts.Render("~/bundles/jqueryval")
@if (this.Culture != GlobalHelper.DefaultCulture)
{
    <script src="@Url.GetScript(“jquery.validate.extension.js”)" defer>
}

与前面一样,我扩展了UrlHelper类,添加了一个用于搜索本地化脚本文件的新方法GetScript。然后,在加载jQuery验证插件之后,我通过引用jQuery. validator .extension.js文件来使用它,但前提是当前区域性与默认区域性不同。

由于前面提到的原因,当我们尝试发送我们的联系人视图而不填写任何必需字段时,我们会获得以下以英语和西班牙语编码的验证消息。

验证消息(英文):

西班牙语的验证消息:

最后,给出了_Contact部分视图的代码片段。cshtml文件:

此部分视图包含一个用于发布数据的简单表单。如果该部分视图是通过http请求上的Get方法呈现的,则将显示一个表单。相反,如果它是在Post请求发送数据后呈现的,则会显示来自Post的结果。没什么可说的了,除非您想深入研究源代码,否则我将使用Post-Redirect-Get模式来完成此工作(请参阅更多信息)。

在验证方面,我想指出的是,当客户端验证被激活时,htmlhelper类中的一些方法,如ValidationMessageFor (见上图),被允许编写html代码来根据模型元数据类中的注释来管理每个输入字段的验证。对于简单的验证,您不需要做任何其他事情。

处理本地化整个视图

到目前为止,我们已经为不太复杂的大型应用程序实现了几乎所有关于本地化的内容。这可能需要一些新特性,比如本地化整个视图。也就是说,每种文化的观点必须非常不同。因此,我们需要向应用程序添加新特性。我将把这个例子应用到法国文化中。此语言的视图将有所不同。我们需要什么来实现这个目标?首先,我们需要为该语言创建新的特定视图。第二,在选择法国文化时,我们必须能够参考这些观点。最后,前面解释的应该也都能正常工作。让我们看看我们如何能完成这一切。

首先,我们将在Views目录下创建一个目录树,如下所示:

注意home目录下的fr-FR 子目录。它将包含法国文化的特定视图。直接位于主目录下的视图将用于默认和西班牙区域性。如果有更多的控制器比主控制器,同样的策略应该采取。

在这一点上,我们必须提供一种基于区域性选择模板视图的方法。为此,我们将创建一个自定义ViewEngine 源自RazorViewEngine (这里有更多信息)。我们将其称为engine MultiLanguageViewEngine。简单解释一下,视图引擎负责搜索、检索和呈现视图、部分视图和布局。在运行MVC 5 Web应用程序时,默认情况下预装了两个视图引擎:Razor和ASPX视图引擎。但是,我们可以删除它们或者添加新的自定义视图引擎,通常在全局的Application_Start方法中。asax文件。在这种情况下,我们将卸载预先存在的默认视图引擎来添加我们的MultiLanguageViewEngine.它将做同样的RazorViewEngine 但是另外,根据文化将查找包含本地化的整个视图模板的特定子目录。让我们来看看存储在App_code文件夹下的多语言eviewengine .cs文件中的代码:

隐藏,收缩,复制Codenamespace MultiLanguageDemo
{
public class MultiLanguageViewEngine : RazorViewEngine
{
private static string _currentCulture = GlobalHelper.CurrentCulture;

    public MultiLanguageViewEngine()
        : this(GlobalHelper.CurrentCulture){
    }

    public MultiLanguageViewEngine(string lang)
    {
        SetCurrentCulture(lang);
    }

    public void SetCurrentCulture(string lang)
    {
       _currentCulture = lang;
       ICollection<string> arViewLocationFormats = 
            new string[] { "~/Views/{1}/" + lang + "/{0}.cshtml" };
       ICollection<string> arBaseViewLocationFormats = new string[] { 
            @"~/Views/{1}/{0}.cshtml", 
            @"~/Views/Shared/{0}.cshtml"};
       this.ViewLocationFormats = arViewLocationFormats.Concat(arBaseViewLocationFormats).ToArray();
    }

    public static string CurrentCulture
    {
        get { return _currentCulture; }
    }
}

}

首先,注意MultiLanguageViewEngine是如何继承RazorViewEngine的。然后,我添加了一个获取支持语言的构造函数。这个构造函数将通过使用新的SetCurrentCulture方法设置新的位置,以查找本地化的整个视图。该方法设置了一个新的位置,以便基于lang param查找视图。这个新路径插入到要搜索的位置数组的第一个位置。字符串数组保存在ViewLocationFormats 属性中。此外,MultiLanguageViewEngine 会返回用于设置此属性的特定区域性。

也就是说,如何处理多语言的eviewengine ?首先,我们将在全局的Application_Start方法中创建这个视图引擎的一个新实例。其次,我们将切换c在线程上设置区域性后立即为自定义视图引擎更新区域性。更详细地说,我们将在我们的BaseController类上重写onactionexecutingmethod。提醒您,这个方法总是在调用控制器上的任何方法之前被调用。

让我们看看全局中的Application_Start方法。asax文件:

隐藏,复制Codeprotected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MultiLanguageViewEngine());

}

粗体代码显示了如何卸载预加载视图引擎的集合,以及如何加载我们的新多语言eviewengine。

现在,让我们再来看看BaseController类中的onactionexecute方法:

隐藏,收缩,复制Code protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
string cultureOnCookie = GetCultureOnCookie(filterContext.HttpContext.Request);
string cultureOnURL = filterContext.RouteData.Values.ContainsKey(“lang”)
? filterContext.RouteData.Values[“lang”].ToString()
: GlobalHelper.DefaultCulture;
string culture = (cultureOnCookie == string.Empty)
? (filterContext.RouteData.Values[“lang”].ToString())
: cultureOnCookie;

if (cultureOnURL != culture)
{
    filterContext.HttpContext.Response.RedirectToRoute("LocalizedDefault", 
        new { lang=culture,
                controller = filterContext.RouteData.Values["controller"],
                action = filterContext.RouteData.Values["action"]
        });
    return;
}

SetCurrentCultureOnThread(culture);

if (culture != MultiLanguageViewEngine.CurrentCulture)
{
    (ViewEngines.Engines[0] as MultiLanguageViewEngine).SetCurrentCulture(culture);
}


base.OnActionExecuting(filterContext);

}

上面的粗体代码显示了如何更新我们的自定义视图引擎。如果线程上存储在区域性变量中的当前区域性与MultiLanguageViewEngine中的当前区域性不同,我们的新引擎将被更新以与Thread同步。我们通过viewengine类的engine集合属性获得对multilanguageviewengine_0索引的访问。请考虑我们在全局中卸载了预加载的视图引擎。asax文件只添加多语言eviewengine。所以,它是第一个。

切换语言从用户界面

正如在前面的屏幕截图中所示,我们的演示应用程序将在右下角有一个用于切换语言的标志列表。因此,这个功能将包含在_Layout中。cshtml文件。该文件将包含项目中每个视图的布局。

一方面,下面是呈现标志的html代码摘录。它是一个简单的选项列表,用于显示表示支持语言的标志。一旦设置了一种语言,所选的标志将用纯绿色边框高亮显示。

为了处理用户选择,我们将包含javascript代码。首先,我创建了一个javascript文件multilanguagedemoc .js来包含应用程序的常用功能。基本上,该文件包含读写cookie的函数。它是基于“名称空间模式”(请参阅这里的更多信息)不需要,这个文件包含在Scripts文件夹中。

一旦用户单击了一个选项,就会创建一个带有所选语言的cookie。在此之后,页面将被重新加载,以根据指定的语言导航到相应的URL。下面是jQuery代码来获得这个:

您必须注意多语言的表情包. cookies的使用。getCookie读取cookie值和多语言的cookie。设置cookie的值。此外,当某个标志被单击时,javascript代码将active-lang类设置为所选的标志,从data-lang属性捕获语言并重新加载视图页面。

的兴趣点

我有一个伟大的时间构建这个小演示应用程序。无论如何,我很难用母语来详细解释一些事情。抱歉。

环境

这个演示程序是用Microsoft Visual Studio 2013开发的。Net Framework 4.5和MVC 5。其他使用的主要组件有jQuery JavaScript库v1.10.2、jQuery验证插件1.11.1、jQuery验证不显眼插件和bootstrap3.0.0。

历史

这是文章的第一个版本。在后面的评论中,我将对应用程序进行一些改进,通过一些示例同时使用全球化问题和数据库对象(如表、存储过程等)的本地化内容来提供应用程序。

,

本文转载于:http://www.diyabc.com/frontweb/news19033.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值