2015-09-01 17 views
5

Tôi đang làm việc để giảm thời gian biên dịch cho một giải pháp C#/ASP.NET lớn. Giải pháp của chúng tôi được dịch sang khoảng một chục ngôn ngữ nước ngoài bằng cách sử dụng phương pháp tập tin resx thông thường. Việc phân tích cú pháp và biên dịch các tệp tài nguyên này làm chậm đáng kể thời gian biên dịch của chúng ta và là một sự thất vọng hàng ngày.Làm cách nào để ngăn chặn việc tạo tài nguyên ngoại ngữ bằng cách ghi đè các mục tiêu MSBuild?

Tôi biết rằng có thể tạo nhà cung cấp tài nguyên tùy chỉnh và thoát khỏi tệp .resx. Bây giờ, hãy giả sử chúng ta phải gắn bó với các tệp .resx.

Bằng cách loại trừ tất cả trừ các tệp .resx miền địa phương mặc định từ tệp .csproj của chúng tôi, tôi có thể cắt thời gian biên dịch của mình thành một nửa. Các nhà phát triển của chúng tôi không cần phải biên soạn một tá ngôn ngữ khác trong quá trình phát triển hàng ngày.

Tôi đang tìm cách ngăn chặn việc biên dịch tệp ngoại ngữ .resx. Tôi đã đưa ra hai phương pháp, và tôi đang tìm kiếm lời khuyên về việc liệu một phương pháp có vượt trội hay không, hoặc liệu có phương pháp nào khác tốt hơn hay không.

Hai tôi đã đi lên với:

  • Viết kịch bản mà có thể loại bỏ và thêm lại trong các file resx không mặc định trong các tập tin csproj khác nhau. Có lẽ chúng tôi sẽ giữ các tệp .csproj tối thiểu trong điều khiển phiên bản và có quy trình xây dựng riêng để thêm lại các tệp .resx theo cách đệ quy để tích hợp lại các bản dịch mới, thực hiện kiểm tra và triển khai các bản dựng của chúng tôi.
  • Hình một cách để ghi đè các mục tiêu MSBuild tích hợp thực hiện phân tích cú pháp và biên dịch resx, vô hiệu hóa hiệu quả chúng cho tất cả trừ ngôn ngữ mặc định. Nhà phát triển có thể bật/tắt hành vi này bằng cờ biên dịch hoặc công cụ xây dựng đơn giản. Tôi chưa đào sâu vào các tệp .target được cung cấp từ Microsoft để xem giải pháp này thực sự hợp lý hoặc bảo trì như thế nào.

Cập nhật

Tôi đã viết kịch bản Powershell sau để di chuyển tất cả EmbeddedResources ngoại ngữ của tôi và biên dịch các yếu tố vào một ItemGroup mới trong đó có một thuộc tính có điều kiện.

$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 

Trả lời

2

Bạn có thể tận dụng các cơ chế hiện có trong MSBuild cho phép bạn xử lý tình huống này, giống như <Choose> yếu tố documentated here và tùy chọn để giới thiệu xây dựng cấu hình của riêng bạn. Nếu các nhà phát triển của bạn chỉ xây dựng các cấu hình Debug trong công việc hàng ngày, bạn thậm chí có thể không cần cấu hình xây dựng của riêng mình: bạn có thể thiết lập dự án của mình để tất cả các tài nguyên ngoại ngữ chỉ được đưa vào bản dựng.

Dự án này phần tập tin sẽ đảm bảo rằng các nguồn lực Ba Lan chỉ được xây dựng trong cấu hình phát hành (mã ngôn ngữ có lẽ sai, nhưng bạn sẽ có được ý tưởng):

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

Trong trường hợp phát triển của bạn cần phải xây dựng Bạn có thể tạo cấu hình ReleaseResx của riêng mình và chỉ bao gồm các tệp .resx ngoại ngữ trong cấu hình đó.

Cả hai đề xuất của bạn cũng sẽ hoạt động, tôi chỉ nghĩ rằng cách tiếp cận này rõ ràng hơn.

+0

Thuộc tính điều kiện trên ItemGroup trông sạch hơn.Nhưng nói chung tôi đồng ý - Tôi muốn hack bên trong msbuild hơn là bao gồm-loại trừ các tập tin bằng kịch bản bên ngoài –

+0

Tuyệt vời! Tôi đang tự hỏi về việc thiết lập và bảo trì kỹ thuật này. Khi thiết lập, tôi hình dung rằng tôi sẽ cần phải chỉnh sửa các tệp csproj theo cách thủ công và đẩy tất cả các tài nguyên không phải miền địa phương mặc định vào cấu trúc Chọn, phải không? Có lẽ kịch bản có thể dễ dàng đủ. Khi các trang và điều khiển mới được thêm vào giải pháp, Visual Studio sẽ tạo các tài nguyên miền địa phương mặc định thông thường của nó bên ngoài cấu trúc Chọn mới này, nơi phần còn lại của tài nguyên miền địa phương mặc định cư trú. Sau đó, tôi cho rằng đó là một câu hỏi về cách chúng tôi đi về việc tích hợp các bản dịch mới trở lại vào các tệp csproj. Điều này là đầy hứa hẹn. –

+0

Thiết lập rất có thể là một bước thủ công, tôi sợ. Bắt các tài nguyên mới vào bản dịch là không có vấn đề nếu các cơ quan dịch thuật của bạn sử dụng các công cụ như SDL Passolo hoặc Alchemy Catalyst. – Jenszcz

Các vấn đề liên quan