我如何通过重写的MSBuild目标prevent外语资源生成? [英] How do I prevent foreign language resource generation by overriding MSBuild targets?

查看:174
本文介绍了我如何通过重写的MSBuild目标prevent外语资源生成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作减少编译时间,大C#/ ASP.NET解决方案。我们的解决方案是使用通常的RESX文件的方法翻译成十几个外国语言。这些资源文件的解析和编译大大减缓我们的编译时间,每天无奈地说。

我知道,它有可能创建自定义资源提供者,并从.resx文件了。现在,请假设我们必须以.resx文件坚持。

通过排除从我们的.csproj文件中的所有,但默认的语言环境.resx文件,我能够削减我们的编译时间缩短了一半。我们的开发者不需要日常的日常开发过程中编译打别的语言。

我在寻找各种方法来prevent外语.resx文件的编制。我想出了两个办法,我在寻找一个人是否优越,或者是否有其他更好的方法的建议。

二,我想出了:


  • 写脚本,可以去掉,并在各种.csproj的文件添加回在非缺省的.resx文件。也许我们会保持在版本控制的最小的.csproj文件,并有重新添加.resx文件单独构建过程递归,以重新整合新的翻译,执行测试,做我们的部署的基础之上。

  • 图的方式来覆盖内置执行的resx解析和编译,有效地禁用它们为所有,但默认语言的MSBuild目标。开发者可以使可能/用一个简单的编译标志禁用此行为或建立开关。我还没有深挖微软提供的文件.TARGET怎么看合理的或可保留该解决方案实际上是。


更新

我写了下面的PowerShell脚本移动我的外语EmbeddedResources和编译元素融入其中有一个条件属性的新的ItemGroup。

$根=C:\\ code \\ solution_root \\#找到所有的csproj文件。
$项目= GET-ChildItem -Path $根-Recurse -ErrorAction SilentlyContinue -Filter *的.csproj |位置对象{$ _拓-eq的.csproj'}#使用哈希表来收集我们搬到了健全检查后缀的唯一列表 - 确保我们没有
#搬迁什么我们并不打算。我这是怎么抓到我在动的JavaScript文件我没打算。
$后缀= @ {}#查找的.resx并结束了.Designer.cs国外资源
#使用正则表达式捕捉到,所以我们可以计算不重复。
$模式=\\(小于区域> \\ w {2}( - \\ w {2,3})\\(Designer.cs | RESX)?)$。的foreach($在$项目项目)
{
    处理{0}-f $ project.FullName    #加载的csproj文件的XML
    $ xmlDoc中=新的XML对象
    $ xmlDoc.Load($ project.FullName)    #设置命名空间的XPath查询
    $ NS =新对象System.Xml.XmlNamespaceManager($ xmlDoc.NameTable)
    $ ns.AddNamespace(NS,$ xmlDoc.DocumentElement.NamespaceURI)    $计数= 0    $嵌入= $ xmlDoc.SelectNodes(// ns:对EmbeddedResource,$ NS)
    $编译= $ xmlDoc.SelectNodes(// ns的:编译,$ NS)    #创建新的条件的ItemGroup节点,如果它不存在。
    #侧面效果 - 每一个的csproj将得到这个新元素,无论它是否
    #包含国外资源。这为我们工作,可能不适合你。
    $ moveToNode = $ xmlDoc.SelectSingleNode(// ns:对的ItemGroup [@条件=`'`$(配置)'=='释放'`],$ NS)
    如果($ moveToNode -eq $ NULL){
        #当创建新的元素,在的namespaceURI从父节点传递。
        #如果我们不这样做,元素将出现空白空间的xmlns一样=,这将打破编译。
        #帽尖https://stackoverflow.com/questions/135000/how-to-$p$pvent-blank-xmlns-attributes-in-output-from-nets-xmldocument        $ conditionAtt = $ xmlDoc.CreateAttribute(「条件」)
        $ conditionAtt.Value ='`$(配置)'=='释放'。
        $ moveToNode = $ xmlDoc.CreateElement(的ItemGroup,$ xmlDoc.Project.NamespaceURI)
        $忽略= $ moveToNode.Attributes.Append($ conditionAtt)
        $忽略= $ xmlDoc.LastChild.AppendChild($ moveToNode)
    }    #环比EmbeddedResource和编译元素。
    的foreach($资源中($中嵌入+ = $编译)){        #排除我在Web项目中的JavaScript文件。
        #这些看起来像* .js.resx或* .js.Designer.cs和我正则表达式都拿到回升。
        #是啊,我可以做一个更好的正则表达式,但我想今天看到我的孩子。
        如果($ resource.Include -notmatchJS \\(Designer.cs |。RESX)$ - 和$ resource.Include -match $模式){            #我们有一个外国语言资源。            #跟踪独特的后缀后报告。
            $后缀= $比赛['区域']
            如果(!$ suffixes.ContainsKey($后缀)){
                $忽略= $ suffixes.Add($后缀,)
            }            $忽略= $ moveToNode.InsertBefore($资源,$空)            #伯爵有多少每个项目的感动。
            $计数+ = 1
        }
    }
    -f $计数$ project.Name在{1} .`n移动{0}资源
    $ xmlDoc.Save($ project.FullName)
}
回声以下独特的后缀进行处理。
$ suffixes.Keys |分类


解决方案

您可以利用的MSBuild的现有机制,使您可以处理这种情况,像<选择> 元素 documentated这里并介绍自己构建配置选项。如果开发人员只有他们每天的日常工作​​中建立调试配置,你可能甚至不需要自己构建的配置:您可以设置项目,使所有外国语言资源仅包含在发布版本

本项目文件部分将确保波兰的资源只建在Release配置(语言codeS很可能是错误的,但你的想法):

 <选择与GT;
  <当条件='$(配置)'=='释放'>
  <&的ItemGroup GT;
    < EmbeddedResource包括=属性\\ Resources.pl.resx>
      <发生器GT; ResXFile codeGenerator< /发电机>
      < LastGenOutput> Resources.pl.Designer.cs< / LastGenOutput>
      <亚型GT;&设计师LT; /亚型GT;
    < / EmbeddedResource>
    <编译包括=属性\\ Resources.pl.Designer.cs>
      < D​​ependentUpon> Resources.pl.resx< / DependentUpon>
      <&AUTOGEN GT;真< / AUTOGEN>
    < /编译>    < - TODO:添加其他语言资源必要的 - >  < /&的ItemGroup GT;
  < /当>
< /选择与GT;

在情况下,你的开发人员需要建立版本的配置,你可以创建自己的配置ReleaseResx,包括外语.resx文件仅在该配置。

这两个您的建议会的工作,我也只是觉得这种方式更干净。

I am working on decreasing compile time for a large C# / ASP.NET solution. Our solution is translated into about a dozen foreign languages using the usual resx file method. The parsing and compiling of these resource files greatly slows down our compile time and is a daily frustration.

I am aware that it is possible to create custom resource providers and get away from .resx files. For now, please assume we must stick with .resx files.

By excluding all but the default locale .resx files from our .csproj files, I am able to cut our compile time in half. Our developers don't need to be compiling a dozen other languages during day-to-day development.

I'm looking for ways to prevent the compilation of the foreign language .resx files. I've come up with two methods, and I'm looking for advice on whether one is superior, or whether there are other better methods.

The two I've come up with:

  • Write scripts that can strip out and add back in the non-default .resx files in the various .csproj files. Perhaps we'd keep the minimal .csproj files in version control, and have a separate build process for re-adding .resx files recursively in order to re-integrate new translations, perform testing and do our deployment builds.
  • Figure a way to override the built-in MSBuild targets that perform resx parsing and compilation, effectively disabling them for all but the default language. Developers could possibly enable/disable this behavior with a simple compile flag or build switch. I've not yet dug deep into the provided .target files from Microsoft to see how reasonable or maintainable this solution actually is.

Update

I wrote the following Powershell script to move all my foreign language EmbeddedResources and Compile elements into a new ItemGroup which has a Conditional attribute.

$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 https://stackoverflow.com/questions/135000/how-to-prevent-blank-xmlns-attributes-in-output-from-nets-xmldocument

        $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

解决方案

You could make use of existing mechanisms in MSBuild that allow you to handle this scenario, like the <Choose> element documentated here and the option to introduce your own build configurations. If your developers only build Debug configurations during their day-to-day work you may not even need your own build configuration: you can set up your project so that that all the foreign language resources are only included in Release builds.

This project file section would make sure that Polish resources are only built in the Release configuration (the language codes are probably wrong, but you get the idea):

<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>

In case your developers need to build Release configurations you can create your own configuration ReleaseResx and include the foreign language .resx files only in that configuration.

Both your suggestions would work, too, I just think this approach is cleaner.

这篇关于我如何通过重写的MSBuild目标prevent外语资源生成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆