Di default, ad oggi, dobbiamo settare 2 parametri: il tipo di
risorsa ed una stringa che contiene il nome della proprietà della
risorsa stessa.
Ma, utilizzando il seguente apprrocio è possibile utilizzare la
risorsa specificando un solo parametro e soprattutto senza l'uso di
alcuna stringa.
In tal modo avremo anche il vantaggio che il compilatore ci
avvertirà di eventuali voci di risorsa rinominate e/o
eliminate.
L'approccio si compone 1 file T4 ed un attributo custom che eredita
da DisplayAttribute.
Il file T4 è il seguente:
<#@ template debug="true" hostspecific="true" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>
<#@ assembly name="VSLangProj" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="EnvDTE80" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#
DTE dte = null;
var serviceProvider = Host as IServiceProvider;
if (serviceProvider != null) {
dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
}
var project = dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject;
try
{
string rootNamespace = project.Properties.Item("RootNamespace").Value.ToString();
var resources = GetResources(project.ProjectItems, "");
foreach(var currentNamespace in resources.Select(s=> s.Namespace).Distinct())
{
var namespaceToPrint = rootNamespace + ((string.IsNullOrWhiteSpace(currentNamespace) ? "" : "." + currentNamespace));
WriteLine(string.Format("namespace {0}", namespaceToPrint));
WriteLine("{");
foreach(var currentClass in resources.Where(w => w.Namespace == currentNamespace).Select(s => s.ClassName).Distinct())
{
WriteLine(string.Format("\tpublic static class {0}Const", currentClass));
WriteLine("\t{");
foreach(var currentElement in resources.Where(w => w.Namespace == currentNamespace && w.ClassName == currentClass))
{
WriteLine(string.Format("\t\tpublic const string {0} = \"{1}\";", currentElement.Key, namespaceToPrint + "." +currentClass + "|" + currentElement.Key));
}
WriteLine("\t}");
}
WriteLine("}");
}
}
catch(Exception ex)
{
Error(ex.ToString());
}
#>
<#+
List<ResourceEntry> GetResources(ProjectItems items, string path)
{
var ret = new List<ResourceEntry>();
foreach(ProjectItem item in items)
{
if(Path.GetExtension(item.Name) == ".resx" && !Regex.IsMatch(item.Name, @".*\.[a-zA-z]{2}(-[a-zA-z]{2})?\.resx"))
{
var filePath = (string)item.Properties.Item("FullPath").Value;
var xml = new XmlDocument();
xml.Load(filePath);
var entries = xml.DocumentElement.SelectNodes("//data");
foreach (XmlElement entryElement in entries)
{
var entry = new ResourceEntry();
if (path.Length > 0)
{
entry.Namespace = path.Substring(1);
}
entry.ClassName = item.Name.Replace(".resx", "");
entry.Key = entryElement.Attributes["name"].Value;
ret.Add(entry);
}
}
if(item.Kind == "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}")
{
ret.AddRange(GetResources(item.ProjectItems, path + "." + item.Name));
}
}
return ret;
}
public class ResourceEntry
{
public string Namespace { get; set; }
public string ClassName { get; set; }
public string Key { get; set; }
}
#>
public class InheritedDisplayAttribute :
DisplayNameAttribute
{
private string _localizedName;
private Dictionary<string, string> _cachedValues;
public InheritedDisplayAttribute(string localizedName)
{
_localizedName = localizedName;
_cachedValues = new Dictionary<string, string>();
}
public override string DisplayName
{
get
{
var cultureCode = Thread.CurrentThread.CurrentUICulture.ToString();
if (!_cachedValues.ContainsKey(cultureCode))
{
_cachedValues.Add(cultureCode, this.ExtractValue());
}
return _cachedValues[cultureCode];
}
}
private string ExtractValue()
{
var resourceType = Type.GetType(_localizedName.Split('|').First());
var propertyName = _localizedName.Split('|').Last();
return resourceType.GetProperty(propertyName).GetValue(null, null).ToString();
}
}
P.S. Il suffisso Const l'ho fissato io nel File T4, ma
possiamo cambiarlo a nostro piacimento.