【问题标题】:Can I use IStringLocalizer in a class which is not a Controller我可以在不是控制器的类中使用 IStringLocalizer
【发布时间】:2017-10-28 02:29:42
【问题描述】:

我了解如何在派生自 Controller 的类中使用 IStringLocalizer 接口,例如如 herehere 所述。

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

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

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

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

【问题讨论】:

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


【解决方案1】:

类是否派生自 Controller 无关紧要。

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

This page 很好地描述了如何创建对象,但我将尝试举例说明它如何与本地化一起使用。

我创建了一个 MyHelper 类。该类期望将定位器对象传递给构造函数。它包含一个属性 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 “Resources”,因此我们必须将资源文件放在此处。我选择了第二个命名选项,所以我的资源文件是

  • 资源\类\MyHelper.resx

正如您在解决方案资源管理器中看到的那样

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

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

(以前的本地化方法(来自 Microsoft)总是使用虚构的资源名称(例如,使用下划线而不是空格)来访问资源。新的 ASP.NET 核心本地化使用原始字符串作为资源名称。)

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

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

【讨论】:

  • 很酷的助手,最好只写Error 而不是_localizer["hello world"],但是你无法像_localizer["hello world", "arg"] 那样格式化它
【解决方案2】:

您可以将共享资源文件(sharedResource.en-US.resx、sharedResource.ko-kr 等)移动到业务层库,方法是创建一个名为“Resources”而不是Web/API 项目。 但请确保 Startup 上的资源位置相对路径的值应为空。

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
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 2017-09-30
    相关资源
    最近更新 更多