diff --git a/KoreBuild-dotnet/build/_k-generate-resx.shade b/KoreBuild-dotnet/build/_k-generate-resx.shade new file mode 100644 index 0000000000..b499e6b0bc --- /dev/null +++ b/KoreBuild-dotnet/build/_k-generate-resx.shade @@ -0,0 +1,177 @@ +use namespace="System" +use namespace="System.Collections.Generic" +use namespace="System.IO" +use namespace="System.Linq" +use namespace="System.Text" +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[] { '\n' }, 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/KoreBuild-dotnet/build/_k-standard-goals.shade b/KoreBuild-dotnet/build/_k-standard-goals.shade index 7433003863..530372a603 100644 --- a/KoreBuild-dotnet/build/_k-standard-goals.shade +++ b/KoreBuild-dotnet/build/_k-standard-goals.shade @@ -181,6 +181,28 @@ default NUGET_FEED = 'https://api.nuget.org/v3/index.json' #make-roslyn-fast ngen-roslyn +#resx + @{ + var cultures = CultureInfo.GetCultures(CultureTypes.NeutralCultures | CultureTypes.InstalledWin32Cultures | CultureTypes.SpecificCultures); + foreach (var file in Directory.EnumerateFiles(BASE_DIR, "*.resx", SearchOption.AllDirectories)) + { + var splitFileName = Path.GetFileNameWithoutExtension(file).Split(new string[] { "." }, StringSplitOptions.None); + + if (splitFileName.Length > 1) + { + var localeString = splitFileName.Last(); + if (!cultures.Any(c => localeString.Equals(c.Name))) + { + UpdateResx(file); + } + } + else + { + UpdateResx(file); + } + } + } + #--quiet @{ AddToE("KOREBUILD_BOWER_INSTALL_OPTIONS", "--quiet"); @@ -330,10 +352,11 @@ macro name="DotnetTest" projectFile='string' testParallel='bool' macro name="XunitTest" projectFile='string' testParallel='bool' xunit-test - macro name='Dnx' command='string' dnxDir='string' dnvmUse='string' dnx macro name="DnxTest" projectFile='string' testParallel='bool' dnx-test - \ No newline at end of file + +macro name="UpdateResx" resxFile='string' + k-generate-resx