我可以在不是Controller的类中使用IStringLocalizer吗?

时间:2017-05-27 07:51:43

标签: asp.net-mvc asp.net-core localization

我理解如何在从Controller派生的类中使用IStringLocalizer接口,例如所描述的herehere

在不从Controller派生的类中使用IStringLocalizer的正确方法是什么?

我找不到解决这个问题的任何例子。

是否始终需要将IStringLocalizer或IStringLocalizerFactory传递给构造函数?

注意。
我知道这是一个相当普遍的问题(Stack Overflow用于具体的编程问题)。背景是我为.NET项目制作了一个本地化工具。我试图找出我的工具必须对源代码进行哪些更改以支持ASP.NET Core项目中的本地化。

2 个答案:

答案 0 :(得分:3)

如果一个类派生自Controller,那无关紧要。

您的对象必须由依赖注入容器创建,而不是使用new运算符,如here所述。如果要在所有类中使用ASP.NET Core本地化机制,则必须采用此模式进行对象创建。

This page给出了如何创建对象的良好描述,但我将尝试举例说明它如何与本地化一起工作。

我创建了一个MyHelper类。该类期望将localizer对象传递给构造函数。它包含一个属性Hello,它返回一个本地化的字符串。

namespace AddingLocalization.Classes
{
  public class MyHelper
  {
    private readonly IStringLocalizer<MyHelper> _localizer;

    public MyHelper(IStringLocalizer<MyHelper> localizer)
    {
      _localizer = localizer;
    }

    public string Hello
    {
      get
      {
        return _localizer["Hello World."];
      }
    }

  }
}

在Startup类的ConfigureServices方法中,我添加了描述here的样板代码,并添加了一行来注册带有依赖注入容器的MyHelper类。

public void ConfigureServices(IServiceCollection services)
{
  services.AddLocalization(opts => opts.ResourcesPath = "Resources");

  services.AddMvc()
          .AddViewLocalization (
               LanguageViewLocationExpanderFormat.Suffix,
               opts => opts.ResourcesPath = "Resources" )
          .AddDataAnnotationsLocalization();

  // This line registers the class MyHelper with the 
  // Dependency Injection Container.      
  services.AddTransient<MyHelper>();
}

在我的控制器类中,我向构造函数添加了一个MyHelper类型的参数,该参数存储在一个成员变量中。

public class HomeController : Controller
{
  private readonly IStringLocalizer<HomeController> _localizer ;
  private readonly MyHelper                         _h ;

  public HomeController ( IStringLocalizer<HomeController> localizer,
                          MyHelper                         h )
  {
    _localizer = localizer;
    _h         = h ;
  }

  ...

  public IActionResult About()
  {
    ViewData["Message"] = _h.Hello ;
    return View();
  }

  ...
}  

因为已经使用依赖注入容器注册了类MyHelper,所以它会创建此对象并自动将其传递给构造函数。这是依赖注入容器执行的魔术。

在About()方法中,我从MyHelper对象中获取属性。

关于代码的问题,但我想确定它实际上会从资源文件中读取字符串。

资源文件的命名约定描述为here

它基于类的全名,没有程序集的名称。在我的情况下,类称为AddingLocalization.Classes.MyHelper,程序集称为AddingLocalization,因此相关名称为Classes.MyHelper。

实际上有两个命名约定,使用点或子目录,所以我们可以调用资源文件之一

  • Classes.MyHelper.resx
  • 类\ MyHelper.resx

ConfigureServices中的样板代码指定了ResourcesPath&#34; Resources&#34;,因此这是我们必须放置资源文件的地方。我选择了第二个命名选项,所以我的资源文件是

  • 资源\类\ MyHelper.resx
正如您在解决方案资源管理器中看到的那样

2017-05-28_09-30-59.png

我们不需要Visual Studio创建文件MyHelper.Designer.cs来访问资源,因此我们应该清除资源文件的CustomTool属性。

enter image description here

这很重要,因为如果我们不禁用自定义工具,名称将不是有效的资源名称,并且可能会生成错误消息。

(以前的本地化方法(来自Microsoft)一直使用伪造的资源名称(例如,使用undercrore而不是space)来访问资源。新的ASP.NET核心本地化使用原始字符串作为资源名称。)

最后我定义了一个资源字符串,如下所示:

enter image description here

我还没有真正尝试用其他语言访问资源(但是),但是本地化程序对象确实正确地读取了资源。

答案 1 :(得分:0)

您可以通过创建一个名为“Resources”而不是 on Web/API 项目。 但请确保启动时资源位置相对路径的值为空。

services.AddLocalization(options => options.ResourcesPath = "");

您的 SharedResouce.cs 文件如下所示。

namespace your.business.library.namespace.Resources
{
    public interface ISharedResource
    {
    }
    public class SharedResource : ISharedResource
    {
        private readonly IStringLocalizer _localizer;

        public SharedResource(IStringLocalizer<SharedResource> localizer)
        {
            _localizer = localizer;
        }

        public string this[string index]
        {
            get
            {
                return _localizer[index];
            }
        }
    }
}

定义访问所需业务类的字段。

private readonly IStringLocalizer<SharedResource> _localizer;

    public AppointmentBookingBL(IStringLocalizer<SharedResource> localizer)
    {
        _localizer = localizer;
    }

从如下资源中获取消息

      public void ModifyBooking(BookingModel model)
        {
            ......... code here
            
                var message = _localizer["BOOKINGNOTAVAILABLE"];
               
            ..... code here
        }