我想覆盖ASP.NET项目的System.ComponentModel.DataAnnotations
字符串。我是否需要制作附属程序集,搞乱自定义构建任务,al.exe
等?即使是,我也找不到如何将.resx
转换为.resources
以将其提供给al.exe
。如果不是,在哪里放.resx.
以及如何命名?
UPD:说清楚:我想使用自定义资源字符串而不是程序集中的默认资源字符串。我不想在使用该字符串的每个地方进行更改。毕竟,资源只是为了覆盖它们而存在。
答案 0 :(得分:4)
菲尔·哈克(Phil Haack)有一篇优秀的文章 Localizing ASP.Net MVC Validation ,它专门指导你完成你的字符串。本文适用于 DataAnnotations
,而不是 ASP.net MVC
。因此,这将有助于您使用 DataAnnotattions 。
下面我列出了在Visual Studio中添加本地化资源的最简单步骤。
Project Properties
对话框。Resources
标签。Properties
文件夹中创建两个文件。
Access Modifier
到 Public
。 要为特定文化添加其他资源文件,您需要这样做。
Project
Solution Explorer
Resources.en-us.resx
。
(用适当的替换'en-us'
代码)Properties
文件夹。Access Modifier
到 Public
。在构建期间,VS会将 .resx 文件转换为 .resource 文件,并为您构建包装类。然后,您可以通过命名空间 YourAssembly.Properties.Resources
。
使用此声明。
using YourAssembly.Properties;
您可以使用以下属性进行装饰:
[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "MyStringName")]
注意:我使用 Properties 文件夹来保持一致性。要使用App_GlobalResources,请在那里移动 .resx 文件,并更改using语句以匹配目录名称。像这样:
using YourAssembly.App_GlobalResources;
编辑:您最接近强类型资源名称的方法是执行以下操作:
public class ResourceNames
{
public const string EmailRequired = "EmailRequired";
}
然后你可以使用这样的属性进行装饰。
[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = ResourceNames.EmailRequired)]
要启用自动客户端区域性检测,请将 globalizationsection 添加到 web.config 文件中。
<configuration>
<system.web>
<globalization enableClientBasedCulture="true" culture="auto:en-us" uiCulture="auto:en-us"/>
</system.web>
<configuration>
在这里,我启用了基于客户端的文化,并将 culture 和 uiculture 设置为“ auto ”,默认为“ EN-US 的。”
创建单独的卫星装配:
MSDN Creating Satellite Assemblies 文章也会有所帮助。 如果您不熟悉附属程序集,请务必阅读 Packaging and Deploying Resources 。
在过去创建附属程序集时,我发现使用VS构建事件很有用。这些是我要采取的步骤。
Class Library
项目。.resx
文件到此项目。Post-Build Event
添加到 Project Properties
对话框中。 (如下所示)示例VS Post-Build脚本:
set RESGEN="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\resgen.exe"
set LINKER="C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\al.exe"
set ASSEMBLY=$(TargetName)
set SOURCEDIR=$(ProjectDir)
Set OUTDIR=$(TargetDir)
REM Build Default Culture Resources (en)
%RESGEN% %SOURCEDIR%en\%ASSEMBLY%.en.resx %SOURCEDIR%en\%ASSEMBLY%.resources
REM Embed Default Culture
%LINKER% /t:lib /embed:%SOURCEDIR%en\%ASSEMBLY%.resources /culture:en /out:%OUTDIR%%ASSEMBLY%.resources.dll
REM Embed English Culture
IF NOT EXIST %OUTDIR%en\ MKDIR $%OUTDIR%en\
%LINKER% /t:lib /embed:%SOURCEDIR%en\%ASSEMBLY%.resources /culture:en /out:%OUTDIR%en\%ASSEMBLY%.resources.dll
REM These are just a byproduct of using the project build event to run the resource build script
IF EXIST %OUTDIR%%ASSEMBLY%.dll DEL %OUTDIR%%ASSEMBLY%.dll
IF EXIST %OUTDIR%%ASSEMBLY%.pdb DEL %OUTDIR%%ASSEMBLY%.pdb
如果您不想使用 ResGen.exe 转换 .resx
文件,则可以执行以下操作。
using System;
using System.Collections;
using System.IO;
using System.Resources;
namespace ResXConverter
{
public class ResxToResource
{
public void Convert(string resxPath, string resourcePath)
{
using (ResXResourceReader resxReader = new ResXResourceReader(resxPath))
using (IResourceWriter resWriter = new ResourceWriter(
new FileStream(resourcePath, FileMode.Create, FileAccess.Write)))
{
foreach (DictionaryEntry entry in resxReader)
{
resWriter.AddResource(entry.Key.ToString(), entry.Value);
}
resWriter.Generate();
resWriter.Close();
}
}
}
}
以这种方式进行转换的潜在缺点之一是需要引用System.Windows.Forms.dll
。您仍然需要使用 Assembly Linker 。
编辑:正如wRAR提醒我们,如果您要为您的程序集签署密钥must match。
答案 1 :(得分:2)
虽然这很奇怪,特别是对于熟悉开源本地化技术的人来说,无法为任何系统程序集甚至是第三方签名的程序集构建附属程序集:
是否可以自动进行,但没有卫星装配,是不可知的,但我对此表示怀疑。
答案 2 :(得分:1)
假设您要覆盖验证属性中的默认错误消息字符串,可以通过设置ErrorMessageResourceName
和ErrorMessageResourceType
属性来实现,如下所示:
[Required(ErrorMessageResourceName = "Required_Username", ErrorMessageResourceType = typeof(MyResourceFile)]
public string Username { get; set; }
您可以使用所需的错误消息创建一个名为MyResourceFile.resx的资源文件,其中包含Required_Username
。
希望这有帮助。
答案 3 :(得分:0)
如果服务器没有安装.NET语言包,那么无论CurrentUICulture设置为什么,您都会在DataAnnotations验证消息中获得英语。这个史诗般的黑客对我们有用。
然后在项目的PreStart方法中,用你项目中的那些覆盖System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources.resourceMan
私有静态字段(告诉你它是一个黑客)。
using System;
using System.Linq;
using System.Reflection;
using System.Resources;
[assembly: WebActivator.PreApplicationStartMethod(typeof(ResourceManagerUtil), nameof(ResourceManagerUtil.PreStart))]
class ResourceManagerUtil
{
public static void PreStart()
{
initDataAnnotationsResourceManager();
}
/// <summary>
/// If the server doesn't have .NET language packs installed then no matter what CurrentUICulture is set to, you'll always get English in
/// DataAnnotations validation messages. Here we override DataAnnotationsResources to use a ResourceManager that uses language .resources
/// files embedded in this assembly.
/// </summary>
static void initDataAnnotationsResourceManager()
{
var embeddedResourceNamespace = "<YourProjectDefaultNamespace>.<FolderYouSavedResourcesFilesIn>";
var dataAnnotationsResourcesName = "System.ComponentModel.DataAnnotations.Resources.DataAnnotationsResources";
var thisAssembly = typeof(ResourceManagerUtil).Assembly;
var dataAnnotationsAssembly = typeof(System.ComponentModel.DataAnnotations.ValidationAttribute).Assembly;
var resourceManager = new ResourceManager(embeddedResourceNamespace + "." + dataAnnotationsResourcesName, thisAssembly);
// Set internal field `DataAnnotationsResources.resourceMan`
var dataAnnotationsResourcesType = dataAnnotationsAssembly.GetType(dataAnnotationsResourcesName);
var resmanProp = dataAnnotationsResourcesType.GetField("resourceMan", BindingFlags.NonPublic | BindingFlags.Static);
resmanProp.SetValue(null, resourceManager);
}
}
答案 4 :(得分:0)
我想提供与Duncan Smart相同的答案,但适用于.NET Core 2.2而不是.NET Framework 4.x。
在这里。
function myEventFunction(event) {
if (event.target.name == "select2") {
event.preventDefault();
} else {
console.log('changed');
}
}
我这样称呼它:
<form onchange="myEventFunction(event)">
<select name="select1">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
<select name="select2">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<select name="select3">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
</form>
此外,我创建了一个using System;
using System.Linq;
using System.Reflection;
using System.Resources;
public static class ResourceManagerHack
{
/// <summary>
/// If the server doesn't have .NET language packs installed then no matter what CurrentUICulture is set to, you'll always get English in
/// DataAnnotations validation messages. Here we override DataAnnotationsResources to use a ResourceManager that uses language .resources
/// files embedded in this assembly.
/// </summary>
public static void OverrideComponentModelAnnotationsResourceManager()
{
EnsureAssemblyIsLoaded();
FieldInfo resourceManagerFieldInfo = GetResourceManagerFieldInfo();
ResourceManager resourceManager = GetNewResourceManager();
resourceManagerFieldInfo.SetValue(null, resourceManager);
}
private static FieldInfo GetResourceManagerFieldInfo()
{
var srAssembly = AppDomain.CurrentDomain
.GetAssemblies()
.First(assembly => assembly.FullName.StartsWith("System.ComponentModel.Annotations,"));
var srType = srAssembly.GetType("System.SR");
return srType.GetField("s_resourceManager", BindingFlags.Static | BindingFlags.NonPublic);
}
internal static ResourceManager GetNewResourceManager()
{
return new ResourceManager($"{typeof(<YourResource>).Namespace}.Strings", typeof(<YourResource>).Assembly);
}
private static void EnsureAssemblyIsLoaded()
{
var _ = typeof(System.ComponentModel.DataAnnotations.RequiredAttribute);
}
}
文件,并在其中填充了the default values,并随意进行了更改。最后,我创建了一个公共的空类public static void Main(string[] args)
{
ResourceManagerHack.OverrideComponentModelAnnotationsResourceManager();
CreateWebHostBuilder(args).Build().Run();
}
。