在Javascript中本地化string

我目前使用.resx文件来pipe理我的服务器端.NET资源。

我正在处理的应用程序还允许开发人员将JavaScript插入到各种事件处理程序中,以便进行客户端validation等。对于本地化我的JavaScript消息和string的最佳方法是什么?

理想情况下,我想将这些string存储在.resx文件中,以保留剩余的本地化资源。

我接受build议。

一个基本的JavaScript对象是一个关联数组,所以它可以很容易地用来存储键/值对。 所以使用JSON ,你可以为每个string创build一个对象,如下所示:

 var localizedStrings={ confirmMessage:{ 'en/US':'Are you sure?', 'fr/FR':'Est-ce que vous êtes certain?', ... }, ... } 

然后你可以得到每个string的语言环境版本,如下所示:

 var locale='en/US'; var confirm=localizedStrings['confirmMessage'][locale]; 

受SproutCore启发您可以设置string的属性:

 'Hello'.fr = 'Bonjour'; 'Hello'.es = 'Hola'; 

然后根据您的区域设置简单地吐出适当的本地化:

 var locale = 'en'; alert( message[locale] ); 

谷歌search了很多,不满意大部分解决scheme,我刚刚发现了一个惊人的/通用的解决scheme,使用T4模板 。 Jochen van Wylick的完整文章可以在这里阅读:

使用T4本地化基于.resx文件的JavaScript资源

主要优点是:

  1. 只有一个地方pipe理资源(即.resx文件)
  2. 支持多种文化
  3. 利用智能感知 – 允许代码完成

缺点:

这个解决scheme的缺点当然是.js文件的大小可能会变得很大。 但是,由于它被浏览器caching,我们不认为这是我们的应用程序的问题。 但是,这种caching也可能导致浏览器找不到从代码调用的资源。


这是如何工作的?

基本上他定义了一个指向你的.resx文件的T4模板。 使用一些C#代码,他遍历每个资源string并将其添加到JavaScript纯键值属性,然后将其输出到名为Resources.js的单个JavaScript文件(如果需要,可以调整名称)。


T4模板 [相应地更改为指向您的.resx文件位置]

 <#@ template language="C#" debug="false" hostspecific="true"#> <#@ assembly name="System.Windows.Forms" #> <#@ import namespace="System.Resources" #> <#@ import namespace="System.Collections" #> <#@ import namespace="System.IO" #> <#@ output extension=".js"#> <# var path = Path.GetDirectoryName(Host.TemplateFile) + "/../App_GlobalResources/"; var resourceNames = new string[1] { "Common" }; #> /** * Resources * --------- * This file is auto-generated by a tool * 2012 Jochen van Wylick **/ var Resources = { <# foreach (var name in resourceNames) { #> <#=name #>: {}, <# } #> }; <# foreach (var name in resourceNames) { var nlFile = Host.ResolvePath(path + name + ".nl.resx" ); var enFile = Host.ResolvePath(path + name + ".resx" ); ResXResourceSet nlResxSet = new ResXResourceSet(nlFile); ResXResourceSet enResxSet = new ResXResourceSet(enFile); #> <# foreach (DictionaryEntry item in nlResxSet) { #> Resources.<#=name#>.<#=item.Key.ToString()#> = { 'nl-NL': '<#= ("" + item.Value).Replace("\r\n", string.Empty).Replace("'","\\'")#>', 'en-GB': '<#= ("" + enResxSet.GetString(item.Key.ToString())).Replace("\r\n", string.Empty).Replace("'","\\'")#>' }; <# } #> <# } #> 

在窗体/视图方面

要获得正确的翻译,如果您使用的是WebForms,请将其添加到您的主文件夹中:

 <script type="text/javascript"> var locale = '<%= System.Threading.Thread.CurrentThread.CurrentCulture.Name %>'; </script> <script type="text/javascript" src="/Scripts/Resources.js"></script> 

如果你使用ASP.NET MVC(像我一样),你可以这样做:

 <script type="text/javascript"> // Setting Locale that will be used by JavaScript translations var locale = $("meta[name='accept-language']").attr("content"); </script> <script type="text/javascript" src="/Scripts/Resources.js"></script> 

MetaAcceptLanguage助手我从Scott Hanselman的这个真棒post中得到:

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

 public static IHtmlString MetaAcceptLanguage<T>(this HtmlHelper<T> html) { var acceptLanguage = HttpUtility.HtmlAttributeEncode( Thread.CurrentThread.CurrentUICulture.ToString()); return new HtmlString( String.Format("<meta name=\"{0}\" content=\"{1}\">", "accept-language", acceptLanguage)); } 

用它

 var msg = Resources.Common.Greeting[locale]; alert(msg); 

使用卫星程序集(而不是resx文件),可以枚举服务器上所有知道语言的string,从而生成一个只包含正确语言string的Javascript对象。

这样的东西适合我们(VB.NET代码):

 Dim rm As New ResourceManager([resource name], [your assembly]) Dim rs As ResourceSet = rm.GetResourceSet(Thread.CurrentThread.CurrentCulture, True, True) For Each kvp As DictionaryEntry In rs [Write out kvp.Key and kvp.Value] Next 

但是,可悲的是,我们还没有find一种方法来处理.resx文件。

JSGettext做的非常出色 – 在后端使用几乎任何语言dynamic加载GNU Gettext .po文件。 谷歌的“dynamicJavascript本地化与Gettext和PHP”find一个演练JSGettext与PHP(我会链接,但这个愚蠢的网站不会让我叹息…)

编辑 : 这应该是链接

我会使用一个对象/数组符号:

 var phrases={}; phrases['fatalError'] ='On no!'; 

然后,您可以交换JS文件,或使用Ajax调用重新定义短语列表。

有一个本地化JavaScript应用程序的库: https : //github.com/wikimedia/jquery.i18n

它可以做参数replace,支持性别(聪明的他/她处理),数字(聪明的复数处理,包括具有多个复数forms的语言)以及某些语言需要的自定义语法规则。

这些string存储在JSON文件中。

唯一的要求是jQuery。

我做了以下操作来为运行HTML5的移动应用程序本地化JavaScript:

1.为每种语言创build一组资源文件,将其称为“en.js”。 每个包含不同的string应用程序如下所示:

 var localString = { appName: "your app name", message1: "blah blah" }; 

2.使用Lazyload根据应用程序的语言环境语言加载适当的资源文件: https : //github.com/rgrove/lazyload

3.通过查询string通过语言代码(因为我使用PhoneGap从Android启动的HTML文件)

4.然后我写下面的代码来dynamic加载适当的资源文件:

 var lang = getQueryString("language"); localization(lang); function localization(languageCode) { try { var defaultLang = "en"; var resourcesFolder = "values/"; if(!languageCode || languageCode.length == 0) languageCode = defaultLang; // var LOCALIZATION = null; LazyLoad.js(resourcesFolder + languageCode + ".js", function() { if( typeof LOCALIZATION == 'undefined') { LazyLoad.js(resourcesFolder + defaultLang + ".js", function() { for(var propertyName in LOCALIZATION) { $("#" + propertyName).html(LOCALIZATION[propertyName]); } }); } else { for(var propertyName in LOCALIZATION) { $("#" + propertyName).html(LOCALIZATION[propertyName]); } } }); } catch (e) { errorEvent(e); } } function getQueryString(name) { name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); var regexS = "[\\?&]" + name + "=([^&#]*)"; var regex = new RegExp(regexS); var results = regex.exec(window.location.href); if(results == null) return ""; else return decodeURIComponent(results[1].replace(/\+/g, " ")); } 

5.从html文件中我可以看到如下的string:

 span id="appName" 

那么,我认为你可以考虑这个。 英语 – 西class牙语例子:

写2 Js脚本,就像这样:

 en-GB.js lang = { date_message: 'The start date is incorrect', ... }; es-ES.js lang = { date_message: 'Fecha de inicio incorrecta', ... }; 

服务器端 – 后面的代码:

 Protected Overrides Sub InitializeCulture() Dim sLang As String sLang = "es-ES" Me.Culture = sLang Me.UICulture = sLang Page.ClientScript.RegisterClientScriptInclude(sLang & ".js", "../Scripts/" & sLang & ".js") MyBase.InitializeCulture() End Sub 

sLang可以是“en-GB”,你知道,取决于当前用户的select…

Javascript调用:

 alert (lang.date_message); 

而且,它的工作,很简单,我认为。

展开diodeus.myopenid.com的答案:让代码写出一个包含所有必需string的JS数组的文件,然后在其他JS代码之前加载适当的文件/脚本。

我们使用MVC并简单地创build一个控制器动作来返回一个本地化的string。 我们在会话中维护用户的文化,并在任何调用检索语言string,AJAX或其他语言之前设置线程文化。 这意味着我们总是返回一个本地化string

我承认,这不是最有效的方法,但在JavaScript中获取本地化的string很less需要,因为大多数本地化在我们的部分视图中完成。

的Global.asax.cs

 protected void Application_PreRequestHandlerExecute(object sender, EventArgs e) { if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState) { // Set the current thread's culture var culture = (CultureInfo)Session["CultureInfo"]; if (culture != null) { Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } } } 

控制器行动

 public string GetString(string key) { return Language.ResourceManager.GetString(key); } 

使用Javascript

 /* Retrieve a localized language string given a lookup key. Example use: var str = language.getString('MyString'); */ var language = new function () { this.getString = function (key) { var retVal = ''; $.ajax({ url: rootUrl + 'Language/GetString?key=' + key, async: false, success: function (results) { retVal = results; } }); return retVal; } }; 

MSDN的做法基本上是:

您为每种受支持的语言和文化创build单独的脚本文件。 在每个脚本文件中,都包含一个JSON格式的对象,其中包含该语言和区域性的本地化资源值。

我不能告诉你你的问题的最佳解决scheme,但恕我直言,这是做到这一点最糟糕的方式。 至less现在你知道怎么做不了。