Sto lavorando alla riduzione del tempo di compilazione per una soluzione C#/ASP.NET di grandi dimensioni. La nostra soluzione è tradotta in circa una dozzina di lingue straniere usando il solito metodo del file resx. L'analisi e la compilazione di questi file di risorse rallenta notevolmente il nostro tempo di compilazione ed è una frustrazione quotidiana.Come impedire la generazione di risorse in lingua straniera sostituendo gli obiettivi di MSBuild?
Sono consapevole del fatto che è possibile creare provider di risorse personalizzate e allontanarsi dai file .resx. Per ora, per favore supponiamo che dobbiamo rimanere con i file .resx.
Escludendo tutti i file .resx delle impostazioni internazionali predefinite dai file .csproj, sono in grado di dimezzare il tempo di compilazione. I nostri sviluppatori non hanno bisogno di compilare una dozzina di altre lingue durante lo sviluppo quotidiano.
Sto cercando modi per impedire la compilazione dei file .resx in lingua straniera. Ho messo a punto due metodi e sto cercando consigli su se uno è superiore o se ci sono altri metodi migliori.
I due mi è venuta in mente:
- script scrivono che possono mettere a nudo fuori e aggiungere di nuovo nei file RESX non predefiniti nei vari file Csproj. Forse manterremo i file .csproj minimi nel controllo di versione e avremo un processo di compilazione separato per aggiungere nuovamente file .resx in modo ricorsivo, al fine di reintegrare nuove traduzioni, eseguire test e realizzare i build di implementazione.
- Figura un modo per ignorare le destinazioni MSBuild incorporate che eseguono analisi e compilazione resx, disabilitandole in modo efficace per tutti tranne la lingua predefinita. Gli sviluppatori potrebbero abilitare/disabilitare questo comportamento con un semplice flag di compilazione o switch di compilazione. Non ho ancora approfondito i file .target forniti da Microsoft per vedere quanto questa soluzione sia ragionevole o gestibile.
Aggiornamento
ho scritto il seguente script PowerShell per spostare tutti i miei EmbeddedResources lingua straniera e compila gli elementi in un nuovo ItemGroup, che ha un attributo condizionale.
$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
L'attributo condizione su ItemGroup sembra più pulito.Ma in generale sono d'accordo: preferirei hackerare all'interno di msbuild piuttosto che includere, escludendo i file dallo script esterno –
Great! Mi sto chiedendo l'installazione e il mantenimento di questa tecnica. Durante l'installazione, immagino che avrò bisogno di modificare manualmente i file csproj e spingere tutte le risorse locali non predefinite nella struttura Scegli, giusto? Probabilmente lo script abbastanza facilmente. Man mano che nuove pagine e controlli vengono aggiunti alla soluzione, Visual Studio creerà le sue solite risorse locali predefinite all'esterno di questa nuova struttura Scegli dove risiedono il resto delle risorse locali predefinite. Quindi suppongo sia tutta una questione di come andiamo a integrare nuove traduzioni nei file csproj. Questo è promettente. –
L'installazione è molto probabilmente un passaggio manuale, temo. Ottenere nuove risorse nelle traduzioni non è un problema se le agenzie di traduzione utilizzano strumenti come SDL Passolo o Alchemy Catalyst. – Jenszcz