diff --git a/build/_k-generate-resx.shade b/build/_k-generate-resx.shade new file mode 100644 index 0000000000..7980266f97 --- /dev/null +++ b/build/_k-generate-resx.shade @@ -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(); + 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() + .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( +@"// +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(" /// ") + .AppendLine(); + foreach (var line in resourceString.Value.Split(new[] { Environment.NewLine }, StringSplitOptions.None)) + { + builder.AppendFormat(" /// {0}", new XText(line)) + .AppendLine(); + } + builder.Append(" /// ") + .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 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; + } + } +} \ No newline at end of file diff --git a/build/_k-standard-goals.shade b/build/_k-standard-goals.shade index 008375877b..f38f899f19 100644 --- a/build/_k-standard-goals.shade +++ b/build/_k-standard-goals.shade @@ -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 \ No newline at end of file + exec + +macro name="UpdateResx" resxFile='string' + k-generate-resx