ASP.NET MVC 3,JavaScript和jQuery中的全球化,国际化和本地化-第1部分

There are several books worth of information to be said about Internationalization (i18n) out there, so I can't solve it all in a blog post. Even 9 pages of blog posts. I like to call it Iñtërnâtiônàlizætiøn, actually.

关于国际化(i18n),有几本值得一说的信息,所以我无法在博客文章中解决所有问题。 甚至9页的博客帖子。 实际上,我喜欢称它为Iñtërnâtiônàlizætiøn

There's a couple of basic things to understand though, before you create a multilingual ASP.NET application. Let's agree on some basic definitions as these terms are often used interchangeably.

在创建多语言ASP.NET应用程序之前,需要了解一些基本知识。 让我们就一些基本定义达成共识,因为这些术语通常可以互换使用。

  • Internationalization (i18n) - Making your application able to support a range of languages and locales

    国际化(i18n)-使您的应用程序能够支持多种语言和语言环境
  • Localization (L10n) - Making your application support a specific language/locale.

    本地化(L10n)-使您的应用程序支持特定的语言/语言环境。
  • Globalization - The combination of Internationalization and Localization

    全球化-国际化与本地化的结合
  • Language - For example, Spanish generally. ISO code "es"

    语言-例如,通常为西班牙语。 ISO代码“ es”
  • Locale - Mexico. Note that Spanish in Spain is not the same as Spanish in Mexico, e.g. "es-ES" vs. "es-MX"

    语言环境-墨西哥。 请注意,西班牙的西班牙语与墨西哥的西班牙语不同,例如“ es-ES”与“ es-MX”

文化与UI文化 (Culture and UICulture)

The User Interface Culture is a CultureInfo instance from the .NET base class library (BCL). It lives on Thread.CurrentThread.CurrentUICulture and if you felt like it, you could set it manually like this:

用户界面区域性是.NET基类库(BCL)中的CultureInfo实例。 它位于Thread.CurrentThread.CurrentUICulture上,如果您喜欢它,可以像这样手动设置它:

Thread.CurrentThread.CurrentUICulture = new CultureInfo("es-MX");

The CurrentCulture is used for Dates, Currency, etc.

CurrentCulture用于日期,货币等。

Thread.CurrentThread.CurrentCulture = new CultureInfo("es-MX"); 

However, you really ought to avoid doing this kind of stuff unless you know what you're doing and you really have a good reason.

但是,除非您知道自己在做什么并且确实有充分的理由,否则您应该避免做这种事情。

The user's browser will report their language preferences in the Accept-Languages HTTP Header like this:

用户的浏览器将在“接受语言HTTP标头”中报告其语言首选项,如下所示:

GET http://www.hanselman.com HTTP/1.1
Connection: keep-alive
Cache-Control: max-age=0
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

See how I prefer en-US and then en? I can get ASP.NET to automatically pass those values and setup the threads with with the correct culture. I need to set my web.config like this:

看看我更喜欢en-US然后再选择en吗? 我可以使ASP.NET自动传递这些值,并以正确的区域性设置线程。 我需要这样设置我的web.config:


   
   
    
    
    
    
...snip...

That one line will do the work for me. At this point the current thread and current UI thread's culture will be automatically set by ASP.NET.

那一条线将为我完成工作。 此时,ASP.NET将自动设置当前线程和当前UI线程的区域性。

伪国际化的重要性 (The Importance of Pseudointernationalization)

Back in 2005 I updated John Robbin's Pseudoizer (and misspelled it then!) and I've just ported it over to .NET 4 and used it for this application. I find this technique for creating localizable sites really convenient because I'm effectively changing all the strings within my app to another language which allows me to spot strings I missed with the tedium of translating strings.

早在2005年,我更新了John Robbin的Pseudoizer (然后拼错了它!),我刚刚将其移植到.NET 4并将其用于此应用程序。 我发现这种用于创建可本地化站点的技术真的很方便,因为我将应用程序中的所有字符串有效地更改为另一种语言,这使我可以发现在翻译字符串的繁琐过程中错过的字符串。

您可以在此处下载.NET Pseudoizer (You can download the .NET Pseudoizer here.)

UPDATE: I've put the source for Pseudoizer up on GitHub. You are welcome to fork/clone it and send pull requests or make your own versions.

更新:我已经在GitHub上放置了Pseudoizer源代码 欢迎您分叉/克隆它并发送拉取请求或制作自己的版本。

Here's an example from that earlier post before I run it through Pseudointernationalization:

这是我通过Pseudointernationalization运行之前的早期帖子中的示例:


    
    
     
     Transaction Download
    
    
View Statement
Select an account below to view or download your available online statements.

I can convert these resources with the pseudoizer like this:

我可以使用伪代码转换这些资源,如下所示:

PsuedoizerConsole examplestrings.en.resx examplestrings.xx.resx

and here's the result:

结果如下:


    
    
     
     [Ŧřäʼnşäčŧįőʼn Đőŵʼnľőäđ !!! !!!]
    
    
[Vįęŵ Ŝŧäŧęmęʼnŧ !!! !!!]
[Ŝęľęčŧ äʼn äččőūʼnŧ þęľőŵ ŧő vįęŵ őř đőŵʼnľőäđ yőūř äväįľäþľę őʼnľįʼnę şŧäŧęmęʼnŧş. !!! !!! !!! !!! !!!]

Cool, eh? If you're working with RESX files a lot, be sure to familiarize yourself with the resgen.exe command-line tool that is included with Visual Studio and the .NET SDK. You have this on your system already. You can move easily between the RESX XML-based file format and a more human- (and translator-) friendly text name=value format like this:

酷吧? 如果您经常使用RESX文件,请确保熟悉Visual Studio和.NET SDK附带的resgen.exe命令行工具。 您已经在系统上拥有此功能。 您可以在基于RESX XML的文件格式和更人性化(和翻译)友好的text name = value格式之间切换,如下所示:

resgen /compile examplestrings.xx.resx,examplestrings.xx.txt

And now they are a nice name=value format, and as I said, I can move between them.

现在它们是一种不错的name = value格式,正如我所说,我可以在它们之间移动。

Accounts.Download.Title=[Ŧřäʼnşäčŧįőʼn Đőŵʼnľőäđ !!! !!!]
Accounts.Statements.Action.ViewStatement=[Vįęŵ Ŝŧäŧęmęʼnŧ !!! !!!]
Accounts.Statements.Instructions=[Ŝęľęčŧ äʼn äččőūʼnŧ þęľőŵ ŧő vįęŵ őř đőŵʼnľőäđ yőūř äväįľäþľę őʼnľįʼnę şŧäŧęmęʼnŧş. !!! !!! !!! !!! !!!]

During development time I like to add this Pseudoizer step to my Continuous Integration build or as a pre-build step and assign the resources to a random language I'm NOT going to be creating, like Polish (with all due respect to the Poles) so I'd make examplestrings.pl.resx and the then we can test our fake language by changing our browser's UserLanguages to prefer pl-PL over en-US.

在开发期间,我想将此Pseudoizer步骤添加到“持续集成”构建中或作为预构建步骤,并将资源分配给我将不愿创建的随机语言,例如波兰语(充分尊重波兰人)因此,我将创建examplestrings.pl.resx,然后我们可以通过更改浏览器的UserLanguages以选择pl-PL而不是en-US来测试我们的伪造语言。

本地化后备 (Localization Fallback)

Different languages take different amounts of space. God bless the Germans but their strings will take an average of 30% more space than English phrases. Chinese will take 30% less. The Pseudoizer pads strings in order to illustrate these differences and encourage you to take them into consideration in your layouts.

不同的语言占用不同的空间。 上帝保佑德国人,但他们的琴弦平均要比英语短语多占用30%的空间。 中国人将少花30%。 Pseudoizer填充字符串以说明这些差异,并鼓励您在布局中考虑它们。

Localization within .NET (not specific to ASP.NET Proper or ASP.NET MVC) implements a standard fallback mechanism. That means it will start looking for the most specific string from the required locale, then fallback continuing to look until it ends on the neutral language (whatever that is). This fallback is handled by convention-based naming. Here is an older, but still excellent live demo of Resource Fallback at ASPAlliance.

.NET中的本地化(不特定于ASP.NET Proper或ASP.NET MVC)实现了一种标准的回退机制。 这意味着它将开始从所需的语言环境中查找最特定的字符串,然后回退以继续查找,直到以中性语言(无论是哪种语言)结束为止。 此后备时间由基于约定的命名处理。 这是ASPAlliance上一个较旧的但仍然非常出色的Resource Fallback现场演示

For example, let's say there are three resources. Resources.resx, Resources.es.resx, and Resources.es-MX.resx.

例如,假设有三种资源。 Resources.resx,Resources.es.resx和Resources.es-MX.resx。

Resources.resx: HelloString=Hello, what's up? GoodbyeString=See ya! DudeString=Duuuude!

Resources.resx: HelloString = Hello,怎么了? GoodbyeString =再见! DudeString = Duuuude!

Resources.es.resx: HelloString=¿Cómo está? GoodbyeString=Adiós!

Resources.es.resx: HelloString =¿ GoodbyeString =Adiós!

Resources.es-MX.resx: HelloString=¿Hola, qué tal?

Resources.es-MX.resx: HelloString =¿Hola,喜欢吗?

Consider these three files in a fallback scenario. The user shows up with his browser requesting es-MX. If we ask for HelloString, he'll get the most specific one. If we ask for GoodbyeString, we have no "es-MX" equivalent, so we move up one to just "es." If we ask for DudeString, we have no es strings at all, so we'll fall all the way back to the neutral resource.

在回退方案中考虑这三个文件。 用户使用其浏览器显示es-MX。 如果我们要求HelloString,他会得到最具体的一个。 如果我们要求GoodbyeString,则没有等效的“ es-MX”,因此我们将其上移至“ es”。 如果我们要求提供DudeString,则根本没有es字符串,因此我们将一路跌回中立资源。

Using this basic concept of fallback, you can minimize the numbers of strings you localize and provide users with not only language specific strings (Spanish) but also local (Mexican Spanish) strings. And yes, I realize this is a silly example and isn't really representative of Spaniards or Mexican colloquial language.

使用这种后备基本概念,您可以最大程度地减少本地化的字符串数量,不仅为用户提供特定于语言的字符串(西班牙语),还为用户提供本地(墨西哥西班牙语)字符串。 是的,我意识到这是一个愚蠢的例子,并不能真正代表西班牙人或墨西哥口语。

视图而不是资源 (Views rather than Resources)

If you don't like the idea of resources, while you will still have to deal with some resources, you could also have difference views for different languages and locales. You can structure your ~/Views folders like Brian Reiter and others have. It's actually pretty obvious once you have bought into the idea of resource fallback as above. Here's Brian's example:

如果您不喜欢资源的想法,尽管您仍然必须处理一些资源,但对于不同的语言和语言环境,您可能也会有不同的看法。 您可以构建〜/ Views文件夹,例如Brian Reiter和其他人的文件夹。 一旦您接受了上述资源回退的想法,这实际上非常明显。 这是Brian的示例:

/Views
/Globalization
/ar
/Home
/Index.aspx
/Shared
/Site.master
/Navigation.aspx
/es
/Home
/Index.aspx
/Shared
/Navigation.aspx
/fr
/Home
/Index.aspx
/Shared
/Home
/Index.aspx
/Shared
/Error.aspx
/Footer.aspx
/Navigation.aspx
/Site.master

Just as you can let ASP.NET change the current UI culture based on UserLanguages or a cookie, you can also control the way that Views are selected by a small override of your favorite ViewEngine. Brian includes a few lines to pick views based on a language cookie on his blog.

正如您可以让ASP.NET根据UserLanguages或cookie更改当前的UI文化一样,您还可以通过对您喜欢的ViewEngine进行小的覆盖来控制选择视图的方式。 Brian在他的博客中包含了几行以基于语言cookie来选择视图

He also includes some simple jQuery to allow a user to override their language with a cookie like this:

他还包括一些简单的jQuery,以允许用户使用如下cookie覆盖其语言:

var mySiteNamespace = {}

mySiteNamespace.switchLanguage = function (lang) {
$.cookie('language', lang);
window.location.reload();
}

$(document).ready(function () {
// attach mySiteNamespace.switchLanguage to click events based on css classes
$('.lang-english').click(function () { mySiteNamespace.switchLanguage('en'); });
$('.lang-french').click(function () { mySiteNamespace.switchLanguage('fr'); });
$('.lang-arabic').click(function () { mySiteNamespace.switchLanguage('ar'); });
$('.lang-spanish').click(function () { mySiteNamespace.switchLanguage('es'); });
});

I'd probably make this a single client event and use data-language or an HTML5 attribute (brainstorming) like this:

我可能会将其作为单个客户端事件,并使用数据语言或HTML5属性(头脑风暴),如下所示:

$(document).ready(function () {
$('.language').click(function (event) {
$.cookie('language', $(event.target).data('lang'));
})
});

But you get the idea. You can set override cookies, check those first, then check the UserLanguages header. It depends on the experience you're looking for and you need to hook it up between the client and server

但是你明白了。 您可以设置替代cookie,先检查它们,然后再检查UserLanguages标头。 这取决于您要寻找的经验,您需要将其挂接到客户端和服务器之间

全球化JavaScript验证(Globalized JavaScript Validation)

If you're doing a lot of client-side work using JavaScript and jQuery, you'll need to get familiar with the jQuery Global plugin. You may also want the localization files for things like the DatePicker and jQuery UI on NuGet via "install-package jQuery.UI.i18n."

如果您正在使用JavaScript和jQuery进行大量客户端工作,则需要熟悉jQuery Global插件。 您可能还需要通过“安装包jQuery.UI.i18n”在NuGet上获取诸如DatePicker和jQuery UI之类的本地化文件。

Turns out the one thing you can't ask your browser via JavaScript is what languages it prefers. That is sitting inside an HTTP Header called "Accept-Language" and looks like this, as it's a weighted list.

事实证明,您无法通过JavaScript询问浏览器的一件事是它喜欢哪种语言。 它位于一个名为“ Accept-Language”的HTTP标头中,看起来像这样,因为它是一个加权列表。

en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2

We want to tell jQuery and friends about this value, so we need access to it from the client side in a different way, so I propose this.

我们想将这个值告诉jQuery和朋友,因此我们需要以不同的方式从客户端访问它,因此我建议这样做。

这很俗气-使用Ajax (This is Cheesy - use Ajax)

We could do this, with a simple controller on the server side:

我们可以通过在服务器端使用一个简单的控制器来做到这一点:

public class LocaleController : Controller {
public ActionResult CurrentCulture() {
return Json(System.Threading.Thread.Current.CurrentUICulture.ToString(), JsonRequestBehavior.AllowGet);
}
}

And then call it from the client side. Ask jQuery to figure it out, and be sure you have the client side globalization libraries you want for the cultures you'll support. I downloaded all 700 jQuery Globs from GitHub. Then I could make a quick Ajax call and get that info dynamically from the server. I also include the locales I want to support as scripts like  /Scripts/globinfo/jquery.glob.fr.js. You could also build a dynamic parser and load these dynamically also, or load them ALL when they show up on the Google or Microsoft CDNs as a complete blob.

然后从客户端调用它。 让jQuery弄清楚它,并确保您具有要支持的文化的客户端全球化库。 我从GitHub下载了所有700个jQuery Globs 。 然后,我可以进行快速Ajax调用,并从服务器动态获取该信息。 我还以/Scripts/globinfo/jquery.glob.fr.js之类的脚本的形式包含了我要支持的语言环境。 您还可以构建一个动态解析器​​并动态地加载它们,或者当它们以完整的Blob形式出现在Google或Microsoft CDN上时全部加载它们。



But that is a little cheesy because I have to make that little JSON call. Perhaps this belongs somewhere else, like a custom META tag.

但这有点俗气,因为我必须进行那个小的JSON调用。 也许这属于其他地方,例如自定义META标签。

少俗气-Meta标签 (Slightly Less Cheesy - Meta Tag)

Why not put the value of this header in a META tag on the page and access it there? It means no extra AJAX call and I can still use jQuery as before. I'll create an HTML helper and use it in my main layout page. Here's the HTML Helper. It uses the current thread, which was automatically set earlier by the setting we added to the web.config.

为什么不将此标头的值放在页面的META标记中并在那里访问呢? 这意味着没有额外的AJAX调用,我仍然可以像以前一样使用jQuery。 我将创建一个HTML帮助器,并在主布局页面中使用它。 这是HTML Helper。 它使用当前线程,该线程是由我们添加到web.config中的设置自动设置的。

namespace System.Web.Mvc
{
public static class LocalizationHelpers
{
public static IHtmlString MetaAcceptLanguage (this HtmlHelper html)
{
var acceptLanguage = HttpUtility.HtmlAttributeEncode(Threading.Thread.CurrentThread.CurrentUICulture.ToString());
return new HtmlString(String.Format(" ",acceptLanguage));
}
}
}

I use this helper like this on the main layout page:

我在主布局页面上像这样使用此帮助程序:





rel="stylesheet" type="text/css" href="@Url.Content(" site.css content>

   


@Html.MetaAcceptLanguage()

...

And the resulting HTML looks like this. Note that this made-up META tag would be semantically different from the Content-Language or the lang= attributes as it's part of the the parsed HTTP Header that ASP.NET decided was our current culture, moved into the client.

生成HTML看起来像这样。 请注意,此组成的META标记在语义上与Content-Language或lang =属性不同,因为它是已解析的HTTP标头的一部分,而该标头是ASP.NET认为是我们当前的文化,并已迁移到客户端。





rel="stylesheet" type="text/css" href="/Content/Site.css">

   



Now I can access it with similar code from the client side. I hope to improve this and support dynamic loading of the JS, however preferCulture isn't smart and actually NEEDS the resources loaded in order to make a decision. I would like a method that would tell me the preferred culture so that I might load the resources on-demand.

现在,我可以从客户端使用类似的代码访问它。 我希望对此进行改进,并支持JS的动态加载,但是preferredCulture并不聪明,实际上需要加载的资源才能做出决定。 我希望有一种方法可以告诉我首选的文化,以便可以按需加载资源。



So what? Now when I am on the client side, my validation and JavaScript is a little smarter. Once jQuery on the client knows about your current preferred culture, you can start being smart with your jQuery. Make sure you are moving around non-culture-specific data values on the wire, then convert them as they become visible to the user.

所以呢? 现在,当我在客户端时,我的验证和JavaScript会更聪明。 一旦客户端上的jQuery了解了您当前的首选文化,就可以开始使用jQuery变得更聪明了。 确保绕过网络上非特定于文化的数据值,然后在用户看到它们时将其转换。

var price = $.format(123.789, "c");
jQuery("#price").html('12345');
var date = $.format(new Date(1972, 2, 5), "D");
jQuery("#date").html(date);
var units = $.format(12345, "n0");
jQuery("#unitsMoved").html(units);

Now, you can apply these concepts to validation within ASP.NET MVC.

现在,您可以将这些概念应用于ASP.NET MVC中的验证。

全球化jQuery非侵入式验证 (Globalized jQuery Unobtrusive Validation  )

Adding onto the code above, we can hook up the globalization to validation, so that we'll better understand how to manage values like 5,50 which is 5.50 for the French, for example. There are a number of validation methods you can hook up, here's number parsing.

在上面的代码上添加代码,我们可以将全球化与验证相关联,以便更好地理解如何管理5,50之类的值,例如,法语为5.50。 您可以使用多种验证方法进行连接,这是数字解析。

$(document).ready(function () {
//Ask ASP.NET what culture we prefer, because we stuck it in a meta tag
var data = $("meta[name='accept-language']").attr("content")
//Tell jQuery to figure it out also on the client side.
$.global.preferCulture(data);

//Tell the validator, for example,
// that we want numbers parsed a certain way!
$.validator.methods.number = function (value, element) {
if ($.global.parseFloat(value)) {
return true;
}
return false;
}
});

If I set my User Languages to prefer French (fr-FR) as in this screenshot:

如果我将用户语言设置为首选法语(fr-FR),如以下屏幕截图所示:

Language Preference Dialog preferring French

Then my validation realizes that and won't allow 5.50 as a value, but will allow 5,50, given this model:

然后,我的验证意识到了这一点,并且不允许使用5.50作为值,但考虑到以下模型,则将允许使用5.5:

public class Example
{
public int ID { get; set; }
[Required]
[StringLength(30)]
public string First { get; set; }
[Required]
[StringLength(30)]
public string Last { get; set; }
[Required]
public DateTime BirthDate { get; set; }
[Required]
[Range(0,100)]
public float HourlyRate { get; set; }
}

I'll see this validation error, as the client side knows our preference for , as a decimal separator.

我会看到此验证错误,因为客户端知道我们偏爱使用十进制分隔符。

NOTE: It seems to me that the [Range] attribute that talks to jQuery Validation doesn't support globalization and isn't calling into the localized methods so it won't work with the , and . decimal problem. I was able to fix this problem by overriding the range method in jQuery like this, forcing it to use the global implementation of parseFloat. Thanks to Kostas in the comments on this post for this info.

注意:在我看来,与jQuery Validation对话的[Range]属性不支持全球化,并且不调用本地化的方法,因此无法与和和一起使用。 十进制问题。 我能够通过像这样重写jQuery中的range方法,强制其使用parseFloat的全局实现来解决此问题。 感谢Kostas在此信息的评论中获得此信息

jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
//Use the Globalization plugin to parse the value
var val = $.global.parseFloat(value);
return this.optional(element) || (val >= param[0] && val <= param[1]);
}
});
Here it is working with validity... 
The Value 4.5 is not valid for Hourly Rate

And here it is in a Danish culture working with [range]:

这里是丹麦文化与[range]的合作:

Localized Range

I can also set the Required Attribute to use specific resources and names and localized them from an ExampleResources.resx file like this:

我还可以将Required Attribute设置为使用特定的资源和名称,并通过ExampleResources.resx文件将其本地化,如下所示:

public class Example
{
public int ID { get; set; }
[Required(ErrorMessageResourceType=typeof(ExampleResources),
ErrorMessageResourceName="RequiredPropertyValue")]
[StringLength(30)]
public string First { get; set; }
...snip...

And see this:

并看到此:

image

NOTE: I'm looking into how to set new defaults for all fields, rather than overriding them individually. I've been able to override some with a resource file that has keys called "PropertyValueInvalid" and "PropertyValueRequired" then setting these values in the Global.asax, but something isn't right.

注意:我正在研究如何为所有字段设置新的默认值,而不是分别覆盖它们。 我已经能够使用具有名为“ PropertyValueInvalid”和“ PropertyValueRequired”的键的资源文件覆盖某些文件,然后在Global.asax中设置这些值,但是有些不正确。

DefaultModelBinder.ResourceClassKey = "ExampleResources";
ValidationExtensions.ResourceClassKey = "ExampleResources";

I'll continue to explore this.

我将继续探索。

动态本地化jQuery DatePicker (Dynamically Localizing the jQuery DatePicker)

Since I know what the current jQuery UI culture is, I can use it to dynamically load the resources I need for the DatePicker. I've installed the "MvcHtml5Templates" NuGet library from Scott Kirkland so my input type is "datetime" and I've added this little bit of JavaScript that says, do we support dates? Are we non-English? If so, go get the right DatePicker script and set it's info as the default for our DatePicker by getting the regional settings given the current global culture.

因为我知道当前的jQuery UI文化是什么,所以我可以使用它动态加载DatePicker所需的资源。 我已经从Scott Kirkland安装了“ MvcHtml5Templates ” NuGet库,因此我的输入类型是“ datetime”,并且添加了这小段JavaScript,表示我们是否支持日期? 我们是非英语的吗? 如果是这样,请获取正确的DatePicker脚本,并通过获取当前全球文化下的区域设置,将其信息设置为DatePicker的默认值。

//Setup datepickers if we don't support it natively!
if (!Modernizr.inputtypes.date) {
if ($.global.culture.name != "en-us" && $.global.culture.name != "en") {
var datepickerScriptFile = "/Scripts/globdatepicker/jquery.ui.datepicker-" + $.global.culture.name + ".js";
//Now, load the date picker support for this language
// and set the defaults for a localized calendar
$.getScript(datepickerScriptFile, function () {
$.datepicker.setDefaults($.datepicker.regional[$.global.culture.name]);
});
}
$("input[type='datetime']").datepicker();
}

Then we set all input's with type=datetime. You could have used a CSS class if you like as well.

然后,我们将所有输入设置为type = datetime。 如果您愿意,也可以使用CSS类。

Now our jQuery DatePicker is French.

现在我们的jQuery DatePicker是法语。

从右到左(body = rtl) (Right to Left (body=rtl))

For languages like Arabic and Hebrew that read Right To Left (RTL) you'll need to change the dir= attribute of the elements you want flipped. Most often you'll change the root element to or change it with CSS like:

对于阅读从右到左(RTL)的阿拉伯语和希伯来语等语言,您需要更改要翻转的元素的dir =属性。 通常,您会将root元素更改为或使用CSS进行更改,例如:

div {
direction:rtl;
}

The point is to have a general strategy, whether it be a custom layout file for RTL languages or just flipping your shared layout with either CSS or an HTML Helper. Often folks put the direction in the resources and pull out the value ltr or rtl depending.

关键是要有一个通用的策略,无论它是用于RTL语言的自定义布局文件,还是只是使用CSS或HTML Helper翻转共享布局。 人们经常将方向放在资源中,然后根据值提取值ltr或rtl。

结论 (Conclusion)

Globalization is hard and requires actual thought and analysis. The current JavaScript offerings are in flux and that's kind.

全球化是困难的,需要实际的思考和分析。 当前JavaScript产品在不断变化,这是一种。

A lot of this stuff could be made boilerplate or automatic, but much of it is a moving target. I'm currently exploring either a NuGet package that sets stuff up for you OR a "File | New Project" template with all the best practices already setup and packaged into one super-package. What's your preference, Dear Reader?

很多这样的东西可以做成样板文件或自动文件,但其中很多是移动目标。 我目前正在研究为您设置内容的NuGet程序包,或“文件|新项目”模板,其中已设置了所有最佳做法并将其打包为一个超级程序包。 亲爱的读者,您的喜好是什么?

完整的脚本 (The Complete Script)

Here's my current "complete" working script that could then be moved into its own file. This is a work in progress, to be sure. Please forgive any obvious mistakes as I'm still learning JavaScript.

这是我当前的“完整”工作脚本,然后可以将其移动到自己的文件中。 可以肯定,这是一项正在进行的工作。 当我仍在学习JavaScript时,请原谅任何明显的错误。


       
       
    <script>
        $(document).ready(function () {
            //Ask ASP.NET what culture we prefer, because we stuck it in a meta tag
            var data = $("meta[name='accept-language']").attr("content")
            //Tell jQuery to figure it out also on the client side.
            $.global.preferCulture(data);
            //Tell the validator, for example,
            // that we want numbers parsed a certain way!
            $.validator.methods.number = function (value, element) {
                if ($.global.parseFloat(value)) {
                    return true;
                }
                return false;
            }
            //Fix the range to use globalized methods
            jQuery.extend(jQuery.validator.methods, {
                range: function (value, element, param) {
                    //Use the Globalization plugin to parse the value
                    var val = $.global.parseFloat(value);
                    return this.optional(element) || (val >= param[0] && val <= param[1]);
                }
            });
            //Setup datepickers if we don't support it natively!
            if (!Modernizr.inputtypes.date) {
                if ($.global.culture.name != 'en-us' && $.global.culture.name != 'en') {
                    var datepickerScriptFile = "/Scripts/globdatepicker/jquery.ui.datepicker-" + $.global.culture.name + ".js";
                    //Now, load the date picker support for this language
                    // and set the defaults for a localized calendar
                    $.getScript(datepickerScriptFile, function () {
                        $.datepicker.setDefaults($.datepicker.regional[$.global.culture.name]);
                    });
                }
                $("input[type='datetime']").datepicker();
            }
        });
    </script>

相关链接 (Related Links)

翻译自: https://www.hanselman.com/blog/globalization-internationalization-and-localization-in-aspnet-mvc-3-javascript-and-jquery-part-1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
此文档是从实际项目总结出来的,互联网上只有“在单一页面进行语言切换”的教程, 没有“一键切换”的解决方案,更没有同时把5种读取资源文件总结在一起的demo。 本文档重点 1.多种读取方式 2.一键全站切换 步骤 一:新建一个asp.netweb应用程序“Internationalization”(图1) 二:右键“Internationalization”--->添加--->添加ASP.NET文件夹--->App_GlobalResources 三:右键“App_GlobalResources”--->添加--->新建项--->资源文件--->GlobalLanguage.resx 四:在GlobalLanguage.resx里添加键值对.(图二) 五:连续复制“GlobalLanguage.resx”两次到“App_GlobalResources”下面,并修改名称为 GlobalLanguage.en-US.resx GlobalLanguage.zh-CN.resx 说明:(为什么会有三个文件呢?系统必须有一个默认文件“GlobalLanguage.resx”,两种语言两个文件.) 六:修改英文和文资源文件里的键值对。 说明(网上大多做法都是把语言设置为浏览器自动识别语言, 这种方式在实际项目一般不用,所以直接讲解用程序来控制) 七:添加language1.aspx (图3,4) 八:添加language2.aspx (图5),在设计模式下“工具”--->“生成本地资源”,会自动添加一个“App_LocalResources” 和第五步一样,添加再添加两个资源文件。 language2.aspx.zh-CN.resx language2.aspx.en-US.resx 说明(一键全站切换的实现方法有多种,这里只讲最有效的,编写一个基类,在里面设置一个全局变量lan,所有 页面都继承这个基类,再通过程序修改变量lan,用Session最简单,但是用户过多时对内存的消耗很大, 还可以用数据库和配置文件,但是最好用Cookie,所以下面以Cookie为例子) 九:新建一个母板页“language.Master”(图6,7) 十:添加language3.aspx (图8,9),必须继承Base类 十一:添加language4.aspx (图10),必须继承Base类

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值