Adding support for generating resx files from build
* Adding support for resx file generation as part of watch command
This commit is contained in:
parent
bacc8d1737
commit
634f069c3c
|
|
@ -0,0 +1,176 @@
|
|||
use namespace="System"
|
||||
use namespace="System.Collections.Generic"
|
||||
use namespace="System.IO"
|
||||
use namespace="System.Linq"
|
||||
use namespace="System.Xml.Linq"
|
||||
|
||||
default resxFile=''
|
||||
|
||||
@{
|
||||
var projectDir = Path.GetDirectoryName(resxFile);
|
||||
var outDirectory = Path.Combine(projectDir, "Properties");
|
||||
var projectName = Path.GetFileName(projectDir.TrimEnd((char)'/'));
|
||||
var namedParameterMatcher = new Regex(@"\{([a-z]\w+)\}", RegexOptions.IgnoreCase);
|
||||
var numberParameterMatcher = new Regex(@"\{(\d+)\}");
|
||||
var generatingEnvironment = new StringBuilder();
|
||||
|
||||
var fileName = Path.GetFileNameWithoutExtension(resxFile);
|
||||
var resourceStrings = new List<ResourceData>();
|
||||
var xml = XDocument.Load(resxFile);
|
||||
|
||||
foreach (var entry in xml.Descendants("data"))
|
||||
{
|
||||
var name = entry.Attribute("name").Value;
|
||||
var value = entry.Element("value").Value;
|
||||
|
||||
bool usingNamedArgs = true;
|
||||
var match = namedParameterMatcher.Matches(value);
|
||||
if (match.Count == 0)
|
||||
{
|
||||
usingNamedArgs = false;
|
||||
match = numberParameterMatcher.Matches(value);
|
||||
}
|
||||
|
||||
var arguments = match.Cast<Match>()
|
||||
.Select(m => m.Groups[1].Value)
|
||||
.Distinct();
|
||||
if (!usingNamedArgs)
|
||||
{
|
||||
arguments = arguments.OrderBy(Convert.ToInt32);
|
||||
}
|
||||
|
||||
resourceStrings.Add(
|
||||
new ResourceData
|
||||
{
|
||||
Name = name,
|
||||
Value = value,
|
||||
Arguments = arguments.ToList(),
|
||||
UsingNamedArgs = usingNamedArgs
|
||||
});
|
||||
}
|
||||
|
||||
generatingEnvironment.AppendFormat(
|
||||
@"// <auto-generated />
|
||||
namespace {0}
|
||||
{{
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class {1}
|
||||
{{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager(""{0}.{1}"", typeof({1}).GetTypeInfo().Assembly);
|
||||
", projectName, fileName);
|
||||
|
||||
foreach (var resourceString in resourceStrings)
|
||||
{
|
||||
generatingEnvironment.AppendLine();
|
||||
RenderHeader(generatingEnvironment, resourceString);
|
||||
RenderProperty(generatingEnvironment, resourceString);
|
||||
|
||||
generatingEnvironment.AppendLine();
|
||||
RenderHeader(generatingEnvironment, resourceString);
|
||||
RenderFormatMethod(generatingEnvironment, resourceString);
|
||||
}
|
||||
|
||||
generatingEnvironment.Append(@"
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace(""{"" + formatterNames[i] + ""}"", ""{"" + i + ""}"");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
");
|
||||
|
||||
Directory.CreateDirectory(outDirectory);
|
||||
var outputPath = Path.Combine(outDirectory, fileName + ".Designer.cs");
|
||||
|
||||
File.WriteAllText(outputPath, generatingEnvironment.ToString());
|
||||
}
|
||||
|
||||
functions @{
|
||||
private static void RenderHeader(StringBuilder builder, ResourceData resourceString)
|
||||
{
|
||||
builder.Append(" /// <summary>")
|
||||
.AppendLine();
|
||||
foreach (var line in resourceString.Value.Split(new[] { Environment.NewLine }, StringSplitOptions.None))
|
||||
{
|
||||
builder.AppendFormat(" /// {0}", new XText(line))
|
||||
.AppendLine();
|
||||
}
|
||||
builder.Append(" /// </summary>")
|
||||
.AppendLine();
|
||||
}
|
||||
|
||||
private static void RenderProperty(StringBuilder builder, ResourceData resourceString)
|
||||
{
|
||||
builder.AppendFormat(" internal static string {0}", resourceString.Name)
|
||||
.AppendLine()
|
||||
.AppendLine(" {")
|
||||
.AppendFormat(@" get {{ return GetString(""{0}""); }}", resourceString.Name)
|
||||
.AppendLine()
|
||||
.AppendLine(" }");
|
||||
}
|
||||
|
||||
private static void RenderFormatMethod(StringBuilder builder, ResourceData resourceString)
|
||||
{
|
||||
builder.AppendFormat(" internal static string Format{0}({1})", resourceString.Name, resourceString.Parameters)
|
||||
.AppendLine()
|
||||
.AppendLine(" {");
|
||||
if(resourceString.Arguments.Count > 0)
|
||||
{
|
||||
builder.AppendFormat(@" return string.Format(CultureInfo.CurrentCulture, GetString(""{0}""{1}), {2});",
|
||||
resourceString.Name,
|
||||
resourceString.UsingNamedArgs ? ", " + resourceString.FormatArguments : null,
|
||||
resourceString.ArgumentNames);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendFormat(@" return GetString(""{0}"");", resourceString.Name);
|
||||
}
|
||||
builder.AppendLine()
|
||||
.AppendLine(" }");
|
||||
}
|
||||
|
||||
private class ResourceData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
public List<string> Arguments { get; set; }
|
||||
|
||||
public bool UsingNamedArgs { get; set; }
|
||||
|
||||
public string FormatArguments
|
||||
{
|
||||
get { return string.Join(", ", Arguments.Select(a => "\"" + a + "\"")); }
|
||||
}
|
||||
|
||||
public string ArgumentNames
|
||||
{
|
||||
get { return string.Join(", ", Arguments.Select(GetArgName)); }
|
||||
}
|
||||
|
||||
public string Parameters
|
||||
{
|
||||
get { return string.Join(", ", Arguments.Select(a => "object " + GetArgName(a))); }
|
||||
}
|
||||
|
||||
public string GetArgName(string name)
|
||||
{
|
||||
return UsingNamedArgs ? name : 'p' + name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,6 +66,14 @@ default Configuration='Release'
|
|||
#make-roslyn-fast
|
||||
ngen-roslyn
|
||||
|
||||
#resx
|
||||
@{
|
||||
foreach (var file in Directory.EnumerateFiles(BASE_DIR, "*.resx", SearchOption.AllDirectories))
|
||||
{
|
||||
UpdateResx(file);
|
||||
}
|
||||
}
|
||||
|
||||
#watch
|
||||
@{
|
||||
var watcher = new FileWatcher(BASE_DIR);
|
||||
|
|
@ -79,7 +87,12 @@ default Configuration='Release'
|
|||
{
|
||||
watcher.WatchFile(file);
|
||||
}
|
||||
|
||||
|
||||
foreach (var file in Directory.EnumerateFiles(BASE_DIR, "*.resx", SearchOption.AllDirectories))
|
||||
{
|
||||
watcher.WatchFile(file);
|
||||
}
|
||||
|
||||
foreach (var dir in Directory.EnumerateDirectories(BASE_DIR, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
watcher.WatchDirectory(dir, ".cs");
|
||||
|
|
@ -90,7 +103,13 @@ default Configuration='Release'
|
|||
{
|
||||
Log.Info("Change detected in " + path);
|
||||
bool restore = path.EndsWith("project.json");
|
||||
|
||||
|
||||
if(path.EndsWith(".resx"))
|
||||
{
|
||||
UpdateResx(path);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
UpdateProjects(BASE_DIR, restore);
|
||||
|
|
@ -117,4 +136,7 @@ macro name='UpdateProjects' basePath='string' restore='bool'
|
|||
k-generate-projects solutionPath='${basePath}' skipNet45='${!restore}'
|
||||
|
||||
macro name='Exec' program='string' commandline='string'
|
||||
exec
|
||||
exec
|
||||
|
||||
macro name="UpdateResx" resxFile='string'
|
||||
k-generate-resx
|
||||
|
|
|
|||
Loading…
Reference in New Issue