如何通过覆盖 MSBuild 目标来防止外语资源生成?

How do I prevent foreign language resource generation by overriding MSBuild targets?

我正在努力减少大型 C#/ASP.NET 解决方案的编译时间。我们的解决方案使用通常的 resx 文件方法翻译成大约十几种外语。这些资源文件的解析和编译,大大拖慢了我们的编译时间,是每天的挫折。

我知道可以创建自定义资源提供程序并摆脱 .resx 文件。现在,请假设我们必须坚持使用 .resx 文件。

通过从我们的 .csproj 文件中排除除默认区域设置 .resx 文件之外的所有文件,我能够将编译时间缩短一半。我们的开发人员不需要在日常开发过程中编译其他十几种语言。

我正在寻找防止编译外语 .resx 文件的方法。我想出了两种方法,我正在寻找一种方法是否更好,或者是否有其他更好的方法。

我想到的两个:


更新

我编写了以下 Powershell 脚本,将我所有的外语 EmbeddedResources 和 Compile 元素移动到一个具有 Conditional 属性的新 ItemGroup 中。

$root = "C:\Code\solution_root\"

# Find all csproj files.
$projects = Get-ChildItem -Path $root -Recurse -ErrorAction SilentlyContinue -Filter *.csproj | Where-Object { $_.Extension -eq '.csproj' }

# Use a hashtable to gather a unique list of suffixes we moved for sanity checking - make sure we didn't 
# relocate anything we didn't intend to. This is how I caught I was moving javascript files I didn't intend to.
$suffixes = @{}

# Find foreign resources ending in .resx and .Designer.cs
# Use a regex capture to so we can count uniques.
$pattern = "\.(?<locale>\w{2}(-\w{2,3})?\.(Designer.cs|resx))$"

foreach ($project in $projects)
{
    "Processing {0}" -f $project.FullName

    # Load the csproj file as XML
    $xmlDoc = new-object XML
    $xmlDoc.Load($project.FullName)

    # Set namespace for XPath queries
    $ns = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable)
    $ns.AddNamespace("ns", $xmlDoc.DocumentElement.NamespaceURI)

    $count = 0 

    $embeds = $xmlDoc.SelectNodes("//ns:EmbeddedResource",$ns)
    $compiles = $xmlDoc.SelectNodes("//ns:Compile",$ns)

    # Create new conditional ItemGroup node if it does not exist.
    # Side-effect - every csproj will get this new element regardless of whether it 
    # contains foreign resources. That works for us, might not for you.
    $moveToNode = $xmlDoc.SelectSingleNode("//ns:ItemGroup[@Condition=`" '`$(Configuration)'=='Release' `"]", $ns)
    if ($moveToNode -eq $null) {
        # When creating new elements, pass in the NamespaceURI from the parent node.
        # If we don't do this, elements will get a blank namespace like xmlns="", and this will break compilation. 
        # Hat tip to 

        $conditionAtt = $xmlDoc.CreateAttribute("Condition")
        $conditionAtt.Value = " '`$(Configuration)'=='Release' "
        $moveToNode = $xmlDoc.CreateElement("ItemGroup", $xmlDoc.Project.NamespaceURI)
        $ignore = $moveToNode.Attributes.Append($conditionAtt)
        $ignore = $xmlDoc.LastChild.AppendChild($moveToNode)
    }

    # Loop over the EmbeddedResource and Compile elements.
    foreach ($resource in ($embeds += $compiles)) {

        # Exclude javascript files which I found in our Web project.
        # These look like *.js.resx or *.js.Designer.cs and were getting picked up by my regex.
        # Yeah, I could make a better regex, but I'd like to see my kids today.
        if ($resource.Include -notmatch "js\.(Designer.cs|resx)$" -and $resource.Include -match $pattern ) {

            # We have a foreign-language resource.

            # Track unique suffixes for reporting later.
            $suffix = $matches['locale']
            if (!$suffixes.ContainsKey($suffix)) {
                $ignore = $suffixes.Add($suffix,"")
            }

            $ignore = $moveToNode.InsertBefore($resource, $null)

            # Count how many we moved per project.
            $count += 1
        }
    }
    "Moved {0} resources in {1}.`n" -f $count, $project.Name
    $xmlDoc.Save($project.FullName)
}
echo "The following unique suffixes were processed."
$suffixes.Keys | sort

您可以利用 MSBuild 中的现有机制来处理这种情况,例如 <Choose> 元素 documentated here 和引入您自己的构建配置的选项。如果您的开发人员在日常工作中只构建 Debug 配置,您甚至可能不需要自己的构建配置:您可以设置您的项目,以便所有外语资源仅包含在 Release 构建中。

此项目文件部分将确保仅在 Release 配置中构建波兰语资源(语言代码可能有误,但您明白了):

<Choose>
  <When Condition=" '$(Configuration)'=='Release' ">
  <ItemGroup>
    <EmbeddedResource Include="Properties\Resources.pl.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.pl.Designer.cs</LastGenOutput>
      <SubType>Designer</SubType>
    </EmbeddedResource>
    <Compile Include="Properties\Resources.pl.Designer.cs">
      <DependentUpon>Resources.pl.resx</DependentUpon>
      <AutoGen>True</AutoGen>
    </Compile>

    <!-- TODO: add other language resources as necessary-->

  </ItemGroup>
  </When>
</Choose>

如果您的开发人员需要构建发布配置,您可以创建自己的配置 ReleaseResx 并仅在该配置中包含外语 .resx 文件。

你的两个建议也行,我只是觉得这种方法更干净。