我原来的问题的答案似乎是“否”。关于本地化,共享项目并没有真正起作用。
然而,本地化可以工作,但有两个问题。
1. 自定义工具 PublicResXFileCodeGenerator 没有运行。
在我自己的工具(这是一个 Visual Studio 扩展)中,我将尝试自己生成 (Resources.designer.cs) 背后的代码。生成它所需的代码非常简单。
这是我的基本功能...
public void GenerateCodeCS ( string resxFullPath, string namespaceName, ITypeResolutionService typeResolver )
{
string BaseName = Path.GetFileNameWithoutExtension ( resxFullPath ) ;
string BaseDir = Path.GetDirectoryName ( resxFullPath ) ;
string FileName = BaseName + ".designer.cs" ;
string FullPath = Path.Combine ( BaseDir, FileName ) ;
using ( var sw = new StreamWriter ( FullPath, false, Encoding.UTF8 ) )
{
sw.WriteLine ( $"namespace {namespaceName}.Properties" ) ;
sw.WriteLine ( "{" );
sw.WriteLine ( " using System;" );
sw.WriteLine ( " using System.Resources;" );
sw.WriteLine ( " using System.Globalization;" );
sw.WriteLine ( " public class Resources" );
sw.WriteLine ( " {" );
sw.WriteLine ( " private static ResourceManager resourceMan;" );
sw.WriteLine ( " private static CultureInfo resourceCulture;" );
sw.WriteLine ();
sw.WriteLine ( " public static global::System.Resources.ResourceManager ResourceManager" );
sw.WriteLine ( " {" );
sw.WriteLine ( " get" );
sw.WriteLine ( " {" );
sw.WriteLine ( " if ( resourceMan == null )" );
sw.WriteLine ( " {" );
sw.WriteLine ($" resourceMan = new ResourceManager(\"{namespaceName}.Properties.Resources\", typeof(Resources).Assembly);" );
sw.WriteLine ( " }" );
sw.WriteLine ( " return resourceMan ;" );
sw.WriteLine ( " }" );
sw.WriteLine ( " }" );
sw.WriteLine ();
sw.WriteLine ( " public static CultureInfo Culture { get => resourceCulture; set => resourceCulture = value; }" );
sw.WriteLine ();
using ( var resxReader = new ResXResourceReader ( resxFullPath, typeResolver ) )
{
resxReader.BasePath = BaseDir ;
resxReader.UseResXDataNodes = true ;
foreach ( DictionaryEntry res in resxReader as IResourceReader )
{
var key = res.Key.ToString() ;
var resxNode = res.Value as ResXDataNode ;
var value = resxNode.GetValue ( typeResolver ) ;
if ( value is string )
{
sw.WriteLine ( $" public static string {key} => ResourceManager.GetString(\"{key}\", resourceCulture);" ) ;
}
}
}
sw.WriteLine ( " }" );
sw.WriteLine ( "}" );
}
}
这会生成一个类似这样的文件
namespace SharedProject.Properties
{
using System;
using System.Resources;
using System.Globalization;
public class Resources
{
private static ResourceManager resourceMan;
private static CultureInfo resourceCulture;
public static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ( resourceMan == null )
{
resourceMan = new ResourceManager("SharedProject.Properties.Resources", typeof(Resources).Assembly);
}
return resourceMan ;
}
}
public static CultureInfo Culture { get => resourceCulture; set => resourceCulture = value; }
public static string Bye_Bye => ResourceManager.GetString("Bye_Bye", resourceCulture);
public static string Ciao_Ciao => ResourceManager.GetString("Ciao_Ciao", resourceCulture);
public static string Hello_World => ResourceManager.GetString("Hello_World", resourceCulture);
}
}
应该可以将其包含在控制台应用程序中并在预构建步骤中运行它。typeResolver 参数可能不是必需的。
2. 资源的命名空间错误。
当资源被编译到目标应用程序中时,它们被赋予应用程序的命名空间,而不是共享项目的命名空间。
由于共享项目中的代码不可能知道目标应用程序的命名空间,因此无法访问资源。
幸运的是,有解决此问题的方法。您要做的是编辑项目文件并将<LogicalName>
属性添加到资源文件中。
实际上,在共享项目中,它不是项目文件(.csproj),而是文件项目项目文件(.projitems)。
在我的示例项目中,资源文件是这样引用的
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LogicalName>SharedProject.Properties.Resources.resources</LogicalName>
</EmbeddedResource>
在这种情况下,SharedProject是共享项目的命名空间,由后面的代码引用(见上文)。
当然该<Generator>
属性是没有意义的,因为自定义工具没有运行。
我不知道通过 GUI 甚至从 Visual Studio 扩展添加属性的任何方法。
使用 ILSpy,我可以看到资源现在使用共享项目的命名空间嵌入到我的应用程序中
并加载资源工作。