Currentjapanese culturee和CurrentUIjapanese culturee的区别

CurrentCulture和CurrentUICulture的区别
CurrentCulture
这个属性用来表示和改变使用者要使用的“地区属性”,地区属性改变后,数字、日期时间等表示格式也随之改变。
注意:一定是“地区属性”,如"zh-cn"、"en-US"等等。
CurrentUICulture
顾名思义,该属性表示使用者所使用的界面语言,可以是“语言属性”,如"zh"、"en"等等。
比如说,用户登录windows后,界面可以是英文的(CurrentUICulture),但数字以及日期的显示方式可以是中国大陆的(CurrentCulture)。
使用Windows控制面板中的“区域和语言”选项,用户就可以改变CurrentCulture的默认设置。使用这个配置,还可以改变文化的默认数字、时间和日期格式。CurrentUICulture不依赖于这个配置,而依赖于操作系统的语言。
在做多语言项目时,往往需要编程动态改变当前应用程序的文化,这是最主要的是必须改变CurrentUICulture,在改变CurrentCulture时需要慎重,因为这种改变将会导致各种转换格式的改变,从而造成配置文件读写转换失败。
  VS2005彻底改变了开发软件多语言版本费时费力的现状,现在用VS2005可以方便地实现一个针对世界上所有语言的地方版本。
1. 文化和区域
  世界分为若干个文化和区域,应用程序必须知道这些文化和区域的区别。文化是基于用户的语言和文化习惯的一组特性。RFC
1766定义了文化的名称,这些名称根据语言和国家或区域的不同在世界各地使用。例如en-AU、en-CA、en-GB和en-US分别用于表示澳大利亚、加拿大、英国和美国的英语。
2. CurrentCulture和CurrentUICulture  应用程序中的文化分为两种类型:用户界面的文化和数字及日期格式的文化。文化与线程相关,有了这两种文化类型,就可以把两个文化设置应用于线程。用线程设置文化时,Thread类提供了属性CurrentCulture和CurrentUICulture。属性CurrentCulture用于设置与格式化和排序选项一起使用的文化,而属性CurrentUICulture用于设置用户界面的语言。
  使用Windows控制面板中的“区域和语言”选项,用户就可以改变CurrentCulture的默认设置。使用这个配置,还可以改变文化的默认数字、时间和日期格式。CurrentUICulture不依赖于这个配置,而依赖于操作系统的语言。
3. 应用程序加载的过程
  对于一个本地化的软件,.Net应用程序都有CurrentCulture和CurrentUICulture两个属性,当它加载时,这两个属性默认为操作系统中预定义的值。.Net应用程序会去程序目录下寻找有文化名称为名字的目录,以及寻找相对应的语言包(附属资源程序集),文件名为assemblyname.resources.dll,如果找到就会加载,如果找不到就会去用默认的(不变的)文化语言包,如果这个语言包也找不到——程序当然会报错。
4. 多语言版CurrentUICulture
  每个窗体都有一个可以设置为 true 或 false 的&Localizable&属性。将该属性设置为
true,就创建了该窗体的多语言版本,Visual Studio 2005
将在幕后为您创建和维护一组已本地化的资源文件。接着,将窗体的Language&属性更改为特定语言(如"中文
(简体)"),则 Visual Studio
会新建一个本地化资源文件,编译后将自动生成该语言的语言包。因此您需要作的就是,更改Language&属性后,直接用该种语言编辑窗体.您可以修改该窗体上的字符串、控件的大小以及位置、甚至替换图片。这样的特性,可以允许您的软件的中文版和英文风格炯异。
5. 不在窗体上的本地化资源
  无需将所有的需本地化资源放置到窗体上,程序中使用的字符串、图片、xml文件等等需要本地化的资源还可以装入到资源文件中。VS2005在项目属性设置中预置了一个资源文件。
  您可以将程序中需要本地化的东西都放在这个资源文件中,在C#程序中您可以以assemblyName.Properties.Resource.resourcename的方式直接引用它。
那项目资源文件中的资源怎样本地化呢?你只需要复制该文件,用新的名称命名,如Resources.zh-CHS.resx,注意到新的名称新增加的部分必须是文化名。接着你在IDE中本地化这个新的资源文件就可以了,剩下的事情,VS2005都帮我们去作了。
6. 多语言版CurrentCulture
  多语言版CurrentCulture主要体现在对一些函数,尤其是Format、ToString函数的使用上,很多函数同string、date类一样,提供在格式化为本地格式的重载函数,这些函数一般带有IFormatProvider参数,允许用编程的方式提供不同文化的格式化的结果。例如:下面的代码生成了法语法国地区的数字与日期的格式化字符串。
int&val&=;
val.ToString("N",&new&CultureInfo("fr-FR")
DateTime d&=new&DateTime(2003,&08,&09);
d.ToString("D",&new&CultureInfo("fr-FR"));
7. 编程改变当前CurrentUICulture和CurrentCulture
  对于许多大型的项目,会产生编程动态改变当前应用程序的文化的需求,在.Net中,这似乎也简单:
&&&&&&//&set
culture for formatting
Thread.CurrentThread.CurrentCulture&=&
&&&&&&//&set
culture for resources
Thread.CurrentThread.CurrentUICulture&=&
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。Nadeem Afana's
blog · ASP.NET MVC 5 Internationalization
Introduction
If your website targets users from different parts of the world, these users might like to see your website content in their own language.
Creating a multilingual website is not an easy task, but it will certainly allow your site to reach more audience.
Fortunately, the .NET Framework already has components that support different languages and cultures.
We will build an ASP.NET MVC 5 web application that contains the following
It can display contents in different languages.
It autodetects the language from the user's browser.
It allows the user to override the language of their browser.
Globalization and Localization in ASP.NET
Internationalization involves Globalization and Localization. Globalization is the process of designing applications that support different cultures. Localization is the process of customizing an application for a given culture.
The format for the culture name is "&languagecode2&-&country/regioncode2&", where &languagecode2& is the language code and &country/regioncode2& is the subculture code. Examples include es-CL for Spanish (Chile) and en-US for English (United States).
Anyway, Internationalization is often abbreviated to "I18N". The abbreviation takes the first and last letters and the number of letters between them,
so 18 stands for the number of letters between the first "I" and the last "N". The same applies to Globalization (G11N), and Localization (L10N).
ASP.NET keeps track of two culture values, the
and . The culture value determines the results of culture-dependent functions, such as the date, number, and currency formatting. The UICulture determines which resources are to be loaded for the page by the ResourceManager. The ResourceManager simply looks up culture-specific resources that is determined by CurrentUICulture.
Every thread in .NET has CurrentCulture and CurrentUICulture objects. So ASP.NET inspects these values when rendering culture-dependent functions. For example, if current thread's culture (CurrentCulture) is set to "en-US" (English, United States), DateTime.Now.ToLongDateString() shows "Saturday, January 08, 2011", but if CurrentCulture is set to "es-CL" (Spanish, Chile) the result will be "s&bado, 08 de enero de 2011".
Now, let&s review the terms used so far:
Globalization (G11N): The process of making an application support different languages and regions.
Localization (L10N): The process of customizing an application for a given language and region.
Internationalization (I18N):
Describes both globalization and localization.
Culture: It is a language and, optionally, a region.
Locale: A locale is the same as a culture.
Neutral culture: A culture that has a specified language, but not a region. (e.g. "en", "es")
Specific culture: A culture that has a specified language and
region. (e.g. "en-US", "en-GB", "es-CL")
Why do we need a region? Isn&t a language alone enough?
You might not need a region at all. It is true that English in the United States is not the same as English in the United Kingdom but if your application just shows English text readable to people from these English-speaking countries, you will not need a region. The problem arises when you need to deal with numbers, dates, and currencies. For example, compare the following output for two different Spanish-speaking regions (Chile, Mexico):
int value = 5600;
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("es-CL");
Console.WriteLine(DateTime.Now.ToShortDateString());
Console.WriteLine(value.ToString("c"));
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("es-MX");
Console.WriteLine(DateTime.Now.ToShortDateString());
Console.WriteLine(value.ToString("c"));
26-07-2011 // Date in es-CL, Spanish (Chile)
$5.600,00 // Currency in es-CL, Spanish (Chile)
26/07/2011 // Date in es-MX, Spanish (Mexico)
$5,600.00 // Currency in es-MX, Spanish (Mexico)
You can notice the difference in date and currency format. The decimal separator in each region is different and can confuse people in the other region. If a Mexican user types one thousand in their culture "1,000", it will be interpreted as 1 (one) in a Chilean culture website. We mainly need regions for this type of reasons and not much for the language itself.
How to Support Different Languages in ASP.NET MVC
There are two ways to incorporate different languages and cultures in ASP.NET MVC:
By using resource strings in all our
site views.
By using different set of views for every language and locale.
By mixing between 1 and 2
Which one is the best? It is a matter of convenience. Some people prefer to use a single view for all languages because it is more maintainable.
While others think replacing views content with code like "@Resources.Something" might clutter the views and will become unreadable.
Some project requirements force developers to implement different views per language.
But sometimes you have no choice where layout has to be different like right-to-left languages.
Even if you set dir="rtl", this may not be enough in real applications unless the project&s UI layout is really simple.
Perhaps, a mix of the two is the best.
Anyway, for this example, it makes sense to use resources since we won&t have any issue with the layout for the Spanish, English, and Arabic languages that we will use.
How can ASP.NET guess the user&s language?
On each HTTP request, there is a header field called Accept-Language which determines which languages the user&s browser supports:
Accept-Language: en-us,q=0.5
This means that my browser prefers English (United States), but it can accept other types of English. The "q" parameter indicates an estimate of the user&s preference for that language. You can control the list of languages using your web browser.
Internet Explorer
Globalizing our Web Site
We will create a new ASP.NET MVC web application and globalize it step by step.
Click "File-&New Project" menu command within Visual Studio to create a new ASP.NET MVC 5 Project.
We'll create a new project using the "MVC" template.
Creating the Model
We'll need a model to create our web application. Add a class named "Person" to the "Models" folder:
public class Person
public string FirstName { }
public string LastName { }
public int Age { }
public string Email { }
public string Biography { }
Internationalizing Validation Messages
Our model presented above contains no validation logic, and this is not the case in normal applications nowadays.
We can use data annotation attributes to add some validation logic to our model. However, in order to globalize validation messages, we need to specify a few extra parameters. The "ErrorMessageResourceType" indicates the type of resource to look up the error message. "ErrorMessageResourceName" indicates the resource name to lookup the error message. Resource manager will pick the correct resource file based on the current culture.
Now modify the "Person" class and add the following attributes:
public class Person
[Display(Name = "FirstName", ResourceType = typeof(Resources.Resources))]
[Required(ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "FirstNameRequired")]
[StringLength(50, ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "FirstNameLong")]
public string FirstName { }
[Display(Name = "LastName", ResourceType = typeof(Resources.Resources))]
[Required(ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "LastNameRequired")]
[StringLength(50, ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "LastNameLong")]
public string LastName { }
[Display(Name = "Age", ResourceType = typeof(Resources.Resources))]
[Required(ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "AgeRequired")]
[Range(0, 130, ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "AgeRange")]
public int Age { }
[Display(Name = "Email", ResourceType = typeof(Resources.Resources))]
[Required(ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "EmailRequired")]
[RegularExpression(".+@.+\\..+", ErrorMessageResourceType = typeof(Resources.Resources),
ErrorMessageResourceName = "EmailInvalid")]
public string Email { }
[Display(Name = "Biography", ResourceType = typeof(Resources.Resources))]
public string Biography { }
Localizing Data Annotations Validation Messages
Because we need to perform data validation on our model using Data Annotations, we will have to add translated resource strings for every culture our site will support. In this case, English, Spanish, and Arabic.
We will store resource files in a separate assembly, so we can reference them in other project types in the future.
Right click on the Solution
and then choose the "Add-&New Project" context menu command. Choose "Class Library" project type and name it "Resources".
Now right click on "Resources" project and then choose "Add-&New Item" context menu command. Choose "Resource File" and name it "Resources.resx". This will be our default culture (en-US) since it has no special endings. Add the following names and values to the file like below:
Remember to mark the resource's access modifier property to "public", so it will be accessible from other projects.
Now create a new resource file and name it "Resources.es.resx" and add the following names and values like below:
Now, do the same for the Arabic version. You may not be able to enter the correct strings by keyboard because your OS may not be configured to accept Arabic. However, you can download the files from the link at the top. Anyway, the resource file is included for reference:
We need to reference "Resources" project from our web application, so that we can read the resource strings right from our web site.
Right click on "References" under our web project "MvcInternationalization", and choose the "Resources" project from Projects tab.
We need to extract the English text from all the views and move it to the resource files.
Here is a trick, instead of typing the namespace name each time (e.g. "@Resources.Resources.LogOn "), we can add this namespace to the views Web.config and type "@Resources.LogOn" instead. Open the Web.config file under the views folder.
Determining Culture
There is a header field called "Accept-Language" that the browser sends on every request. This field contains a list of culture names (language-country) that the user has configured in their browser. The problem is that this culture may not reflect the real user's preferred language, such as a computer in a public place.
We should allow the user to choose a language explicitly and allow them even to change it. In order to do this sort of things,
we need to store the user's preferred language in a store, which can be perfectly a cookie.
We will create a base controller that inspects the cookie contents first, if there is no cookie, we will use the "Accept-Language" field sent by their browser.
Create a controller and name it "BaseController" like below:
public class BaseController : Controller
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
string cultureName =
// Attempt to read the culture cookie from Request
HttpCookie cultureCookie = Request.Cookies["_culture"];
if (cultureCookie != null)
cultureName = cultureCookie.V
cultureName = Request.UserLanguages != null && Request.UserLanguages.Length & 0 ?
Request.UserLanguages[0] :
// obtain it from HTTP header AcceptLanguages
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentC
return base.BeginExecuteCore(callback, state);
Make sure all controllers in this project inherit from this BaseController.
The base controller checks if the cookie exists, and sets the current thread cultures to that cookie value. Of course, because cookie content can be manipulated on the client side, we should always validate its value using a helper class called "CultureHelper". If the culture name is not valid, the helper class returns the default culture.
CultureHelper Class
The CultureHelper is basically a utility that allows us to store culture names we are implementing in our site:
public static class CultureHelper
// Valid cultures
private static readonly List&string& _validCultures = new List&string& { "af", "af-ZA", "sq", "sq-AL", "gsw-FR", "am-ET", "ar", "ar-DZ", "ar-BH", "ar-EG", "ar-IQ", "ar-JO", "ar-KW", "ar-LB", "ar-LY", "ar-MA", "ar-OM", "ar-QA", "ar-SA", "ar-SY", "ar-TN", "ar-AE", "ar-YE", "hy", "hy-AM", "as-IN", "az", "az-Cyrl-AZ", "az-Latn-AZ", "ba-RU", "eu", "eu-ES", "be", "be-BY", "bn-BD", "bn-IN", "bs-Cyrl-BA", "bs-Latn-BA", "br-FR", "bg", "bg-BG", "ca", "ca-ES", "zh-HK", "zh-MO", "zh-CN", "zh-Hans", "zh-SG", "zh-TW", "zh-Hant", "co-FR", "hr", "hr-HR", "hr-BA", "cs", "cs-CZ", "da", "da-DK", "prs-AF", "div", "div-MV", "nl", "nl-BE", "nl-NL", "en", "en-AU", "en-BZ", "en-CA", "en-029", "en-IN", "en-IE", "en-JM", "en-MY", "en-NZ", "en-PH", "en-SG", "en-ZA", "en-TT", "en-GB", "en-US", "en-ZW", "et", "et-EE", "fo", "fo-FO", "fil-PH", "fi", "fi-FI", "fr", "fr-BE", "fr-CA", "fr-FR", "fr-LU", "fr-MC", "fr-CH", "fy-NL", "gl", "gl-ES", "ka", "ka-GE", "de", "de-AT", "de-DE", "de-LI", "de-LU", "de-CH", "el", "el-GR", "kl-GL", "gu", "gu-IN", "ha-Latn-NG", "he", "he-IL", "hi", "hi-IN", "hu", "hu-HU", "is", "is-IS", "ig-NG", "id", "id-ID", "iu-Latn-CA", "iu-Cans-CA", "ga-IE", "xh-ZA", "zu-ZA", "it", "it-IT", "it-CH", "ja", "ja-JP", "kn", "kn-IN", "kk", "kk-KZ", "km-KH", "qut-GT", "rw-RW", "sw", "sw-KE", "kok", "kok-IN", "ko", "ko-KR", "ky", "ky-KG", "lo-LA", "lv", "lv-LV", "lt", "lt-LT", "wee-DE", "lb-LU", "mk", "mk-MK", "ms", "ms-BN", "ms-MY", "ml-IN", "mt-MT", "mi-NZ", "arn-CL", "mr", "mr-IN", "moh-CA", "mn", "mn-MN", "mn-Mong-CN", "ne-NP", "no", "nb-NO", "nn-NO", "oc-FR", "or-IN", "ps-AF", "fa", "fa-IR", "pl", "pl-PL", "pt", "pt-BR", "pt-PT", "pa", "pa-IN", "quz-BO", "quz-EC", "quz-PE", "ro", "ro-RO", "rm-CH", "ru", "ru-RU", "smn-FI", "smj-NO", "smj-SE", "se-FI", "se-NO", "se-SE", "sms-FI", "sma-NO", "sma-SE", "sa", "sa-IN", "sr", "sr-Cyrl-BA", "sr-Cyrl-SP", "sr-Latn-BA", "sr-Latn-SP", "nso-ZA", "tn-ZA", "si-LK", "sk", "sk-SK", "sl", "sl-SI", "es", "es-AR", "es-BO", "es-CL", "es-CO", "es-CR", "es-DO", "es-EC", "es-SV", "es-GT", "es-HN", "es-MX", "es-NI", "es-PA", "es-PY", "es-PE", "es-PR", "es-ES", "es-US", "es-UY", "es-VE", "sv", "sv-FI", "sv-SE", "syr", "syr-SY", "tg-Cyrl-TJ", "tzm-Latn-DZ", "ta", "ta-IN", "tt", "tt-RU", "te", "te-IN", "th", "th-TH", "bo-CN", "tr", "tr-TR", "tk-TM", "ug-CN", "uk", "uk-UA", "wen-DE", "ur", "ur-PK", "uz", "uz-Cyrl-UZ", "uz-Latn-UZ", "vi", "vi-VN", "cy-GB", "wo-SN", "sah-RU", "ii-CN", "yo-NG" };
// Include ONLY cultures you are implementing
private static readonly List&string& _cultures = new List&string& {
// first culture is the DEFAULT
"es", // Spanish NEUTRAL culture
// Arabic NEUTRAL culture
/// &summary&
/// Returns true if the language is a right-to-left language. Otherwise, false.
/// &/summary&
public static bool IsRighToLeft()
return System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.IsRightToL
/// &summary&
/// Returns a valid culture name based on "name" parameter. If "name" is not valid, it returns the default culture "en-US"
/// &/summary&
/// &param name="name" /&Culture's name (e.g. en-US)&/param&
public static string GetImplementedCulture(string name)
// make sure it's not null
if (string.IsNullOrEmpty(name))
return GetDefaultCulture(); // return Default culture
// make sure it is a valid culture first
if (_validCultures.Where(c =& c.Equals(name, StringComparison.InvariantCultureIgnoreCase)).Count() == 0)
return GetDefaultCulture(); // return Default culture if it is invalid
// if it is implemented, accept it
if (_cultures.Where(c =& c.Equals(name, StringComparison.InvariantCultureIgnoreCase)).Count() & 0)
// accept it
// Find a close match. For example, if you have "en-US" defined and the user requests "en-GB",
// the function will return closes match that is "en-US" because at least the language is the same (ie English)
var n = GetNeutralCulture(name);
foreach (var c in _cultures)
if (c.StartsWith(n))
// It is not implemented
return GetDefaultCulture(); // return Default culture as no match found
/// &summary&
/// Returns default culture name which is the first name decalared (e.g. en-US)
/// &/summary&
/// &returns&&/returns&
public static string GetDefaultCulture()
return _cultures[0]; // return Default culture
public static string GetCurrentCulture()
return Thread.CurrentThread.CurrentCulture.N
public static string GetCurrentNeutralCulture()
return GetNeutralCulture(Thread.CurrentThread.CurrentCulture.Name);
public static string GetNeutralCulture(string name)
if (!name.Contains("-"))
return name.Split('-')[0]; // Read first part only. E.g. "en", "es"
We should populate "_cultures" manually. The "_cultures" dictionary stores the list of culture names our site supports. The nice part of this utility class is that it serves similar cultures. For example, if a user is visiting our site from the United Kingdom (en-GB), a culture which is not implemented in our site, he or she will see our site in English using "en-US" (English, United States). This way, you don't have to implement all cultures unless you really care about currency, date format, etc. One important thing to mention is that we added all specific cultures for the Spanish language. For example, we are implementing "es" Spanish in general without any region where a date looks like this "30/07/2011". Now suppose a nerd is coming from Chile (es-CL), it would be very nice display dates in their culture format (30-07-2011) instead of the neutral one. It does not matter if we don&t have a resource file for any of these cultures. ResourceManager can pick a neutral culture when it cannot find a specific culture file, this automatic mechanism is called fallback.
Controllers
Visual Studio has created a controller named "HomeCotnroller" for us, so we'll use it for simplicity. Modify the "HomeController.cs" so that it looks like below:
public class HomeController : BaseController
public ActionResult Index()
return View();
[HttpPost]
public ActionResult Index(Person per)
return View();
public ActionResult SetCulture(string culture)
// Validate input
culture = CultureHelper.GetImplementedCulture(culture);
// Save culture in a cookie
HttpCookie cookie = Request.Cookies["_culture"];
if (cookie != null)
cookie.Value =
// update cookie value
cookie = new HttpCookie("_culture");
cookie.Value =
cookie.Expires = DateTime.Now.AddYears(1);
Response.Cookies.Add(cookie);
return RedirectToAction("Index");
The "SetCulture" action allows the user to change their current culture and stores it in a cookie called "_culture". We are not restricted to cookies, we could instead save the culture name in Session or elsewhere, but cookies are really lightweight since they do not take any type of space on server side.
Creating a View Template
Now we will implement the View associated with the HomeController's Index action. First delete the existing Index.cshtml file under "Views/Home" folder. Now to implement the view right-click within the "HomeController.Index()" method and select the "Add View" command to create a view template for our home page:
Click OK and replace the existing view if any. When we click the "Add" button, a view template of our "Create" view (which renders the form) is created. Modify it so it looks like below:
@model MvcInternationalization.Models.Person
ViewBag.Title = Resources.AddP
var culture = System.Threading.Thread.CurrentThread.CurrentUICulture.Name.ToLowerInvariant();
@helper selected(string c, string culture)
if (c == culture)
@:checked="checked"
&h2&@Resources.AddPerson&/h2&
@using(Html.BeginForm("SetCulture", "Home"))
&fieldset&
&legend&@Resources.ChooseYourLanguage&/legend&
&div class="control-group"&
&div class="controls"&
&label for="en-us"&
&input name="culture" id="en-us" value="en-us" type="radio" @selected("en-us", culture) /& English
&div class="control-group"&
&div class="controls"&
&label for="es"&
&input name="culture" id="es" value="es" type="radio" @selected("es", culture) /& Espa&ol
&div class="control-group"&
&div class="controls"&
&label for="ar"&
&input name="culture" id="ar" value="ar" type="radio" @selected("ar", culture) /& ???????
&/fieldset&
@using (Html.BeginForm())
@Html.AntiForgeryToken()
&div class="form-horizontal"&
@Html.ValidationSummary(true)
&div class="form-group"&
@Html.LabelFor(model =& model.FirstName, new { @class = "control-label col-md-2" })
&div class="col-md-10"&
@Html.EditorFor(model =& model.FirstName)
@Html.ValidationMessageFor(model =& model.FirstName)
&div class="form-group"&
@Html.LabelFor(model =& model.LastName, new { @class = "control-label col-md-2" })
&div class="col-md-10"&
@Html.EditorFor(model =& model.LastName)
@Html.ValidationMessageFor(model =& model.LastName)
&div class="form-group"&
@Html.LabelFor(model =& model.Age, new { @class = "control-label col-md-2" })
&div class="col-md-10"&
@Html.EditorFor(model =& model.Age)
@Html.ValidationMessageFor(model =& model.Age)
&div class="form-group"&
@Html.LabelFor(model =& model.Email, new { @class = "control-label col-md-2" })
&div class="col-md-10"&
@Html.EditorFor(model =& model.Email)
@Html.ValidationMessageFor(model =& model.Email)
&div class="form-group"&
@Html.LabelFor(model =& model.Biography, new { @class = "control-label col-md-2" })
&div class="col-md-10"&
@Html.EditorFor(model =& model.Biography)
@Html.ValidationMessageFor(model =& model.Biography)
&div class="form-group"&
&div class="col-md-offset-2 col-md-10"&
&input type="submit" value="@Resources.Create" class="btn btn-default" /&
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
&script type="text/javascript"&
(function ($) {
$("input[type = 'radio']").click(function () {
$(this).parents("form").submit(); // post form
})(jQuery);
The javascript code simply post back the form to set the culture. The "selected" helper is used to mark the appropriate culture radio button as checked.
Of course, we should not forget about partial views too
@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated)
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
@Html.AntiForgeryToken()
&ul class="nav navbar-nav navbar-right"&
@Html.ActionLink(User.Identity.GetUserName(), "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })
&li&&a href="javascript:document.getElementById('logoutForm').submit()"&@Resources.LogOff&/a&&/li&
&ul class="nav navbar-nav navbar-right"&
&li&@Html.ActionLink(Resources.Register, "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })&/li&
&li&@Html.ActionLink(Resources.LogOn, "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })&/li&
Left-to-right or Right-to-left
HTML supports rtl languages too, so we need to make sure our main HTML tag has the appropriate direction. Modify the _Layout.cshtml file
to look like the following:
&!DOCTYPE html&
&html lang="@CultureHelper.GetCurrentNeutralCulture()" dir="@(CultureHelper.IsRighToLeft() ? "rtl" : "ltr")"&
&meta charset="utf-8" /&
&meta name="viewport" content="width=device-width, initial-scale=1.0"&
&title&@ViewBag.Title - ASP.NET MVC Internationalization&/title&
@Styles.Render("~/Content/css" + (CultureHelper.IsRighToLeft() ? "-rtl" : ""))
@Scripts.Render("~/bundles/modernizr")
&div class="navbar navbar-inverse navbar-fixed-top"&
&div class="container"&
&div class="navbar-header"&
&button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"&
&span class="icon-bar"&&/span&
&span class="icon-bar"&&/span&
&span class="icon-bar"&&/span&
@Html.ActionLink("ASP.NET MVC Internationalization", "Index", "Home", null, new { @class = "navbar-brand" })
&div class="navbar-collapse collapse"&
&ul class="nav navbar-nav"&
@Html.Partial("_LoginPartial")
&div class="container body-content"&
@RenderBody()
&p&@DateTime.Now&/p&
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap" + (CultureHelper.IsRighToLeft() ? "-rtl" : ""))
@RenderSection("scripts", required: false)
Now we need to provide basically two sets of CSS and JS files: One for left-to-right languages and one for right-to-left languages.
Because MVC default template is using Bootstrap, we need to install the RTL version of bootstrap files. For this, open the package
manager console (aka Nuget) by choosing Tools -& Library Package Manager -& Package Manager Console and type:
Install-Package Twitter.Bootstrap.RTL
Make sure you have the two files bootstrap-rtl.js and bootstrap-rtl.css
We need to create two bundles: one for RTL and one for LTR. Modify the file BundleConfig.cs and add the following:
bundles.Add(new ScriptBundle("~/bundles/bootstrap-rtl").Include(
"~/Scripts/bootstrap-rtl.js",
"~/Scripts/respond.js"));
bundles.Add(new StyleBundle("~/Content/css-rtl").Include(
"~/Content/bootstrap-rtl.css",
"~/Content/site.css"));
Try It Out
Run the website now. Notice that client side validation is working nicely. Click on radio buttons to switch between cultures, and notice how right-to-left language is showing correctly. Using separate views allowed us to control how to position elements, and have made our views clean and readable.
How to store culture in the URL instead of a cookie?
There can be different reasons why you want the culture to be part of your website url (such as search engine indexing). Anyway. First let's fist define
the culture to be part of our routes. Edit RouteConfig.cs like below:
public static void RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{culture}/{controller}/{action}/{id}",
defaults: new {culture = CultureHelper.GetDefaultCulture(), controller = "Home", action = "Index", id = UrlParameter.Optional }
Notice the we used the default culture in case it is missing. Now modify the base controller:
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
string cultureName = RouteData.Values["culture"]
// Attempt to read the culture cookie from Request
if (cultureName == null)
cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ? Request.UserLanguages[0] : // obtain it from HTTP header AcceptLanguages
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
if (RouteData.Values["culture"] as string != cultureName) {
// Force a valid culture in the URL
RouteData.Values["culture"] = cultureName.ToLowerInvariant(); // lower case too
// Redirect user
Response.RedirectToRoute(RouteData.Values);
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentC
return base.BeginExecuteCore(callback, state);
The final step is to modify the SetCulture action in HomeController.cs
public ActionResult SetCulture(string culture)
// Validate input
culture = CultureHelper.GetImplementedCulture(culture);
RouteData.Values["culture"] =
// set culture
return RedirectToAction("Index");
NOTE: To force the default culture appear in the URL, simply set the default value for culture in RouteConfig.cs to string.Empty
Building a multilingual web application is not an easy task. but it's worth it
especially for web applications targeting users from all over the world,
something which many sites do. It is true that globalization is not the first
priority in site development process, however, it should be well planned early
in the stage of development so it can be easily implemented in the future.
Luckily, ASP.NET supports globalization and there are plenty of .NET classes
that are handy. We have seen how to create an ASP.NET MVC application that
supports 3 different languages, including a right-to-left one, which requires a
different UI layout. Anyway, here is a summary of how to globalize a
site in ASP.NET MVC:
Add a base controller from which all controllers inherit. This
controller will intercept the view names returned and will adjust them depending
on the current culture set.
Add a helper class that stores the list of culture names that the site will
Create resource files that contain translation of all string messages. (e.g.
Resources.resx, Resources.es.resx, Resources.ar.resx, etc )
Update views to use localized text.
Localize javascript files.
I hope this helps! Any questions or comments are welcome!
0b0c9d0f-482c-443e-855d-3c1ea7c9ffb2|98|4.7
Related postsDownload multilingual NerdDinner!
In my previous blog post, ASP.NET MVC 3 Internationalizatio...
Download code!
In the previous post, ASP.NET MVC 5 Internationalization, I...Download code
It would be nice if a web site can show times local to the regi...
About the authorNadeem Afana
Senior Software DeveloperTwitter
C# Extension methods and how they work}

我要回帖

更多关于 lts current区别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信