如何在ASP.NET Core中获取Resx文件的字符串? 在MVC中,我使用ResxResourceReader获取字符串。但是在ASP.NET Core中我无法做到相同。
如何在ASP.NET Core中获取Resx文件的字符串? 在MVC中,我使用ResxResourceReader获取字符串。但是在ASP.NET Core中我无法做到相同。
.NET Core在资源文件方面的改变我认为有些不足和令人困惑(花了我几天时间才弄明白),但这是你需要做的:
如JustAMartin在评论中所说:如果您计划将您的SharedResource文件放在Resources文件夹中并将其命名空间设置为以Resources结尾,则不要设置
o.ResourcesPath = "Resources"
,只需使用services.AddLocalization()
,否则它将开始搜索Resources.Resources文件夹,但此文件夹不存在。
services.AddLocalization(o => o.ResourcesPath = "Resources");
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("en-GB"),
new CultureInfo("de-DE")
};
options.DefaultRequestCulture = new RequestCulture("en-US", "en-US");
// You must explicitly state which cultures your application supports.
// These are the cultures the app supports for formatting
// numbers, dates, etc.
options.SupportedCultures = supportedCultures;
// These are the cultures the app supports for UI strings,
// i.e. we have localized resources for.
options.SupportedUICultures = supportedCultures;
});
在任何你想要存储resx文件的项目中创建一个文件夹 - 默认情况下,称之为"Resources".
使用特定的区域设置和稍后要查找的文件名创建一个新的resx文件:如果你有一个共享的resx文件,你可以这样做:SharedResource.en-US.resx。然后关闭自动生成代码,因为现在它没用了。
在与resx文件相同的位置创建一个名为"SharedResource"的类。它可以是空的,只需要存在,以便稍后引用它。
无论在哪里使用你的资源,在这个例子中使用IoC注入IStringLocalizer< SharedResource >并命名为"_localizer"或其他名称。
最后,你可以通过_localizer["My_Resource_Name"]引用Resource文件中的条目。
通过在同一文件夹中创建名为"SharedResource.de-DE.resx"(或其他名称)的新的resx文件来添加另一种语言。
"Resource"文件夹将被用于查找所有程序集。因此,这个文件夹可能会变得非常混乱,特别是如果你开始在这里添加特定于视图的内容。
我理解开发人员的初衷,但他们放弃了过多的内容。人们可以编写并添加翻译的内容,而不必实际翻译任何东西。他们让开发人员更容易从一开始就考虑翻译,但最终却让实际使用翻译的开发人员工作量增加了很多。现在我们不能自动生成任何东西。我们必须IoC注入引用以访问它们(除非你想要使用ServiceLocater反模式中的静态方法)。所有名称都是硬编码字符串,因此现在如果你拼错了一个翻译,它会直接返回你给它的字符串,从而打败了首次具有翻译目的的初衷,并且可能需要在这个上面包装一层,以便你不会过度依赖常量。
说实话,我无法相信有人认为这是一个好主意。为什么要为那些不关心翻译的开发人员努力呢?
最终,我创建了一个基于这种风格的包装器。唯一好的一点是,如果你决定从数据库获取资源,以上代码不需要做任何更改,但现在你必须添加资源条目、将其添加到接口中,然后实现它以将其重新提取。我使用nameof(),所以我不需要使用常量,但这仍然很脆弱,因为如果属性名称或resx文件名更改,它将打破翻译而没有任何崩溃——我可能需要一个集成测试来确保我不会得到相同的值。
public interface ICommonResource
{
string ErrorUnexpectedNumberOfRowsSaved { get; }
string ErrorNoRecordsSaved { get; }
string ErrorConcurrency { get; }
string ErrorGeneric { get; }
string RuleAlreadyInUse { get; }
string RuleDoesNotExist { get; }
string RuleInvalid { get; }
string RuleMaxLength { get; }
string RuleRequired { get; }
}
public class CommonResource : ICommonResource
{
private readonly IStringLocalizer<CommonResource> _localizer;
public CommonResource(IStringLocalizer<CommonResource> localizer) =>
_localizer = localizer;
public string ErrorUnexpectedNumberOfRowsSaved => GetString(nameof(ErrorUnexpectedNumberOfRowsSaved));
public string ErrorNoRecordsSaved => GetString(nameof(ErrorNoRecordsSaved));
public string ErrorConcurrency => GetString(nameof(ErrorConcurrency));
public string ErrorGeneric => GetString(nameof(ErrorGeneric));
public string RuleAlreadyInUse => GetString(nameof(RuleAlreadyInUse));
public string RuleDoesNotExist => GetString(nameof(RuleDoesNotExist));
public string RuleInvalid => GetString(nameof(RuleInvalid));
public string RuleMaxLength => GetString(nameof(RuleMaxLength));
public string RuleRequired => GetString(nameof(RuleRequired));
private string GetString(string name) =>
_localizer[name];
}
ResXFileCodeGenerator
生成编译时属性(例如在此处看到:https://christianspecht.de/2017/11/29/fixing-resourcedesignercs-generation-in-net-core/)。 - Dejanservices.AddLocalization();
而不是之前的方法。我知道这对你来说可能有些晚了,但这可能会帮助其他人 :) - ProgrammingLlama旧的做法(比如在asp.net中)是创建一个默认资源文件,例如MyResources.resx,以及其他针对不同文化的文件,例如MyResources.fr.resx等,并通过MyResources.MyValue1从中检索值。创建MyResources.resx将生成一个包含所有资源值作为静态属性的.cs文件。
.Net Core建议使用 IStringLocalizer<T>
,其中T是由您创建的与资源文件名称匹配的类。您可以开始开发而不需要任何资源文件,稍后再添加它们。您必须在控制器上注入 (IStringLocalizer< MyResources > localizer),然后使用 _localizer["MyValue1"]获取值。
您可以查看 .net core 官方文档这里
如果需要更直接的替换,我已经创建了ResXResourceReader.NetStandard,它重新封装了ResXResourceReader
和ResXResourceWriter
用于 .NET Standard(这也适用于 .NET Core)。