在 ASP.NET MVC 中将资源字符串暴露给 JavaScript 文件的最佳方式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16122791/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 03:20:41  来源:igfitidea点击:

Best way to expose resource strings to JavaScript files in ASP.NET MVC?

javascriptasp.netasp.net-mvclocalization

提问by Pol

It's easy to use resource strings (.resx) in Razor view, but how to do that in JavaScript files? Currently I'm manually passing strings from Razor view to scripts in JavaScript constructor argument but I would like a way to do this more automatically so I don't have to pass each and every resource string that I need.

在 Razor 视图中使用资源字符串 (.resx) 很容易,但如何在 JavaScript 文件中使用呢?目前,我正在手动将字符串从 Razor 视图传递到 JavaScript 构造函数参数中的脚本,但我想要一种更自动地执行此操作的方法,因此我不必传递我需要的每个资源字符串。

回答by davaus

The solution I have used is to use a Razor to create a json object that contains all the resource strings for a given application area eg "Customers". Like so:

我使用的解决方案是使用 Razor 创建一个 json 对象,该对象包含给定应用程序区域的所有资源字符串,例如“客户”。像这样:

<script  type="text/jscript">

@{

    ResourceSet resourceSet = JsCustomersRes.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
    var sbInitial = " var CustomersResourceObj = {"; 
    var sb = new StringBuilder(sbInitial);
    var resEnum = resourceSet.GetEnumerator(); 
    while (resEnum.MoveNext()) 
    {
        if (sb.ToString() != sbInitial)
        {
            sb.Append(",");
        }
        sb.Append("\"" + resEnum.Key + "\":\"" + resEnum.Value.ToString().Replace("\r\n", "").Replace("\"", "\\"") + "\"");
    } 
    sb.Append("}");
} 

@(Html.Raw( sb.ToString()));

The resource file "JsCustomersRes" can be placed along with the particular controller views directory or in the shared view directory. It should have "Custom Tool" set to "PublicResXFileCodeGenerator" in the file advanced properties.

资源文件“JsCustomersRes”可以与特定的控制器视图目录或共享视图目录一起放置。它应该在文件高级属性中将“自定义工具”设置为“PublicResXFileCodeGenerator”。

You can then get the resource string from the json object in your script:

然后,您可以从脚本中的 json 对象获取资源字符串:

var resString = CustomersResourceObj[key];

where "key" is the key string of the resource string you want. Just add the Razor as a partial view to your layout page or individual page as you require and that's it!

其中“key”是您想要的资源字符串的键字符串。只需根据需要将 Razor 作为部分视图添加到您的布局页面或单个页面,就是这样!

回答by equiman

My solution is based on this http://codethug.com/2013/08/02/using-net-resources-in-javascript/and quoting Tim Larson's (author) words:

我的解决方案基于此http://codethug.com/2013/08/02/using-net-resources-in-javascript/并引用 Tim Larson(作者)的话:

We don't have to do much to determine what culture to use. The web browser, when it hits the server, includes header information showing what cultures it supports. ASP.Net automatically puts this information into CultureInfo.CurrentUICulture. We pass this into the GetResourceSet method, which then returns the resource set that matches the current browser settings.

Thus, if the browser is set to French, the French resources, and only the French Resources, will be returned.

我们不需要做太多事情来决定使用什么文化。Web 浏览器在访问服务器时包含显示其支持的文化的标头信息。ASP.Net 会自动将此信息放入 CultureInfo.CurrentUICulture。我们将其传递给 GetResourceSet 方法,然后该方法返回与当前浏览器设置匹配的资源集。

因此,如果浏览器设置为法语,将返回法语资源,并且仅返回法语资源。

Steep 1. Create a resource file RLocalizedText.resxinto App_GlobalResources folder. And create fill it with all the string.

陡峭 1.在 App_GlobalResources 文件夹中创建资源文件RLocalizedText.resx。并创建用所有字符串填充它。

Steep 2. Create ResourcesController

步骤 2. 创建ResourcesController

using System.Web.Mvc;

namespace PortalACA.Controllers
{
    public class ResourcesController : Controller
    {
        // GET: Resources
        public ActionResult Index()
        {
            Response.ContentType = "text/javascript";
            return View();
        }
    }
}

Steep 3. Create Index.cshtmlview from ResourcesController

陡峭 3.从 ResourcesController创建Index.cshtml视图

@using System.Collections
@using System.Globalization
@using System.Resources
@using Resources
@{
    Layout = null;
    // Get a set of resources appropriate to
    // the culture defined by the browser
    ResourceSet resourceSet =
      @RLocalizedText.ResourceManager.GetResourceSet
        (CultureInfo.CurrentUICulture, true, true);
}

// Define the empty object in javascript
var Resources = {};
@foreach (DictionaryEntry res in resourceSet)
{
    // Create a property on the javascript object for each text resource
    @:[email protected] = "@Html.Raw(
        HttpUtility.JavaScriptStringEncode(res.Value.ToString()))";
}

The choose where you want use it.

选择你想要使用它的地方。

Steep 4A (Layout). If you want use it on whole site, then need put this script reference on _Layout(Shared View) over @RenderSection

陡峭的4A(布局)。如果您想在整个站点上使用它,则需要将此脚本引用放在@RenderSection上的_Layout(共享视图)上

<script src="@Url.Content("~/Resources/Index")"></script>
@RenderSection("scripts", required: false)

Steep 4B (View). If you want to see only in some views.

陡峭的4B(视图)。如果您只想在某些视图中查看。

@section Scripts
{
  <script src="@Url.Content("~/Resources/Index")"></script>
}

Steep 5. Now it is the time to use it. Select a view where you need see the strings on Resources files and put this code.

陡峭 5. 现在是使用它的时候了。选择您需要查看资源文件字符串的视图并放置此代码。

@section Scripts
{
  <script>
    $(document).ready(function () {
      alert(Resources.General_Excepcion);
    });
  </script>
}

That's all Folks! Hope it help others!

这就是所有的人!希望它能帮助别人!

回答by bitwalker

I would do something like the following:

我会做类似以下的事情:

<script type="text/javascript">
    var resourceStrings = {
        @foreach (var resource in ViewBag.Resources)
        {
            { '@resource.Key' : '@resource.Value' },
        }
    };
</script>

This assumes that you've created a dictionary of resource key/values and set a view bag property with the dictionary. You can then access those resources as a javascript object lookup.

这假设您已经创建了一个资源键/值字典,并使用该字典设置了一个视图包属性。然后,您可以将这些资源作为 javascript 对象查找来访问。

$('label[name=gender]').html(resourceStrings['gender']);

You could potentially have a dictionary of dictionaries if you wanted to access keys by culture:

如果您想按文化访问键,您可能有一个字典字典:

$('label[name=gender]').html(resourceStrings['en_US']['gender']);

回答by Okan Kocyigit

Create an action which expose your Resource Set to json

创建一个将您的资源集公开给 json 的操作

public class HomeController: Controller {

   [Route("localization.js")]
   public ActionResult Localization()
   {
       ResourceSet resourceSet = Globalization.Resources.ResourceManager.GetResourceSet(
                                       CultureInfo.CurrentUICulture, true, true);
       var result = resourceSet.Cast<DictionaryEntry>()
           .ToDictionary(x => x.Key.ToString(),
                    x => x.Value.ToString());

       return View((object)(JsonConvert.SerializeObject(result)));
   }

}

add ~/Views/Home/localization.cshtmlfile with the content

添加~/Views/Home/localization.cshtml包含内容的文件

@model string
@{ 
    Layout = null;
}
var Resources = @Html.Raw(Model);

In Web.config, add the handler for localization.js

在 中Web.config,添加处理程序localization.js

 <system.webServer>
   <handlers>
     <add name="Localization" path="*/localization.js" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
   </handlers>
 </system.webServer>

Call the action in your _Layout.cshtmlor wherever you want to expose your Resources

在您_Layout.cshtml或您想公开资源的任何地方调用操作

<script type="text/javascript">
    @(Html.Action("Localization", "Home"))
</script>

Result

结果

<script type="text/javascript">
    var Resources = {"HelloWorld" : "こんにちは世界", "NiceJob": "いいね!" };
    //Sample usage
    console.log(Resources.HelloWorld);
    console.log(Resources.NiceJob);
</script>

回答by HarryKak

I prefer to create a Javascript object that has all the resources as properties. Also I avoid creating a partial view. Instead I pass the required language as a parameter to the script. This way you can add the script in a global template, instead of adding it in each page.

我更喜欢创建一个具有所有资源作为属性的 Javascript 对象。我也避免创建局部视图。相反,我将所需的语言作为参数传递给脚本。这样您就可以在全局模板中添加脚本,而不是在每个页面中添加它。

Basically I have a helper static class with the following static method:

基本上我有一个带有以下静态方法的辅助静态类:

    public static JavaScriptResult JavascriptResources(ResourceManager manager, string resourceObjectName, CultureInfo culture)
    {
        ResourceSet resourceSet = manager.GetResourceSet(culture, true, true);

        StringBuilder sb = new StringBuilder();

        sb.AppendFormat("var {0}=new Object();", resourceObjectName);

        var enumerator = resourceSet.GetEnumerator();
        while (enumerator.MoveNext())
        {
            sb.AppendFormat("{0}.{1}='{2}';", resourceObjectName, enumerator.Key,
                System.Web.HttpUtility.JavaScriptStringEncode(enumerator.Value.ToString()));
        }

        return new JavaScriptResult()
        {
            Script = sb.ToString()
        };
    }

In the project I've added the following controller:

在项目中,我添加了以下控制器:

public class ResourcesController : Controller
{
    [OutputCache(Duration = 36000, VaryByParam = "lang")]
    // Duration can be many hours as embedded resources cannot change without recompiling.
    // For the clients, I think 10 hours is good.
    public JavaScriptResult Index(string lang)
    {
        var culture = new CultureInfo(lang);
        return Helpers.JavascriptResources(Resources.Client.ResourceManager,
            "Client", culture);
    }
}

Note that I have added a parameter give the global javascript object any name you want. In the example above, I could access the translations like this in JS:

请注意,我添加了一个参数,为全局 javascript 对象提供您想要的任何名称。在上面的例子中,我可以在 JS 中访问这样的翻译:

alert(Client.Info_Message);

Now to call this script, I register it in the default template (for example in ~/Shared/_layout.cshtml)

现在要调用这个脚本,我将它注册到默认模板中(例如在~/Shared/_layout.cshtml

<script type="text/javascript" src="~/resources/?lang=@(ViewBag.Language)"></script>

The best way for this to work, is to create an action filter to automatically enter the language in the ViewData. This could be done like this:

最好的方法是创建一个动作过滤器来自动在 ViewData 中输入语言。这可以这样做:

public class LanguageInViewBagAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var controller = filterContext.Controller;
        if (controller != null)
            controller.ViewBag.Language = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
    }
}

You can then decorate controllers or actions with it where applicable, for example:

然后,您可以在适用的情况下用它装饰控制器或动作,例如:

[LanguageInViewBag]
public class HomeController : Controller

or register as a global filter in /App_start/Filters.cs

或注册为全局过滤器 /App_start/Filters.cs

Note: My implementation assumes you set per request the Thread.CurrentThread.CurrentCultureto the user's culture. This way the actionfilter knows the currently selected language.

注意:我的实现假设您将每个请求设置为Thread.CurrentThread.CurrentCulture用户的文化。这样 actionfilter 就知道当前选择的语言。

回答by AgathoSAreS

All solutions, better or worse, have been mentioned. Just for completion I want to propose another solution: Do not set text from within Javascript.

已经提到了所有解决方案,无论好坏。只是为了完成,我想提出另一个解决方案:不要在 Javascript 中设置文本。

Adding words from Javascript to the page that are not directly loaded from the server, is as if you would write css in an html file.

将来自 Javascript 的单词添加到页面,而不是直接从服务器加载,就像在 html 文件中编写 css 一样。

回答by Moby's Stunt Double

You could do that in a more graceful way using AJAX and a JSON ActionResult.

您可以使用 AJAX 和 JSON ActionResult 以更优雅的方式做到这一点。

<button />
<label for="gender"></label>

<script type="text/javascript">
    $("button").click(function () {
        $('label[for=gender]').load('@Url.Action("ResourceLabel", new { labelKey = "Gender" })');
    });
</script>

And server side, greatly simplified, but you get the idea:

和服务器端,大大简化,但你明白了:

public ContentResult ResourceLabel(string labelKey) {
    return Content(ResourceClass.GetString(labelKey));
}