From 9cb6176ed2755edd8a0822ebc6e9ef90795df889 Mon Sep 17 00:00:00 2001 From: Roman Konecny Date: Thu, 20 Apr 2023 14:39:02 +0200 Subject: [PATCH 1/2] Localize LiveLogger strings. Rework some areas to enable localization. --- src/MSBuild.UnitTests/MockTerminal.cs | 2 + src/MSBuild/LiveLogger/ITerminal.cs | 5 + src/MSBuild/LiveLogger/LiveLogger.cs | 95 +++++++++------- src/MSBuild/LiveLogger/Terminal.cs | 8 +- src/MSBuild/Resources/Strings.resx | 96 ++++++++++++++++ src/MSBuild/Resources/xlf/Strings.cs.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.de.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.es.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.fr.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.it.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.ja.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.ko.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.pl.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.pt-BR.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.ru.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.tr.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.zh-Hans.xlf | 105 ++++++++++++++++++ src/MSBuild/Resources/xlf/Strings.zh-Hant.xlf | 105 ++++++++++++++++++ 18 files changed, 1531 insertions(+), 40 deletions(-) diff --git a/src/MSBuild.UnitTests/MockTerminal.cs b/src/MSBuild.UnitTests/MockTerminal.cs index 915a1e15c8b..97c63c2fea0 100644 --- a/src/MSBuild.UnitTests/MockTerminal.cs +++ b/src/MSBuild.UnitTests/MockTerminal.cs @@ -99,6 +99,8 @@ public void EndUpdate() public void Write(ReadOnlySpan text) { AddOutput(text.ToString()); } public void WriteColor(TerminalColor color, string text) => AddOutput(text); public void WriteColorLine(TerminalColor color, string text) { AddOutput(text); AddOutput("\n"); } + public string RenderColor(TerminalColor color, string text) => text; + public void WriteLine(string text) { AddOutput(text); AddOutput("\n"); } public void WriteLineFitToWidth(ReadOnlySpan text) { diff --git a/src/MSBuild/LiveLogger/ITerminal.cs b/src/MSBuild/LiveLogger/ITerminal.cs index 6a2f1e67faa..ac00d58f1a6 100644 --- a/src/MSBuild/LiveLogger/ITerminal.cs +++ b/src/MSBuild/LiveLogger/ITerminal.cs @@ -63,6 +63,11 @@ internal interface ITerminal : IDisposable /// Writes a string to the output using the given color. Or buffers it if was called. /// void WriteColorLine(TerminalColor color, string text); + + /// + /// Return string representing text wrapped in VT100 color codes. + /// + string RenderColor(TerminalColor color, string text); } /// diff --git a/src/MSBuild/LiveLogger/LiveLogger.cs b/src/MSBuild/LiveLogger/LiveLogger.cs index 5bcb21138d1..d8d24aa4e7b 100644 --- a/src/MSBuild/LiveLogger/LiveLogger.cs +++ b/src/MSBuild/LiveLogger/LiveLogger.cs @@ -42,9 +42,20 @@ internal record NodeStatus(string Project, string? TargetFramework, string Targe { public override string ToString() { + string duration = Stopwatch.Elapsed.TotalSeconds.ToString("F1"); + return string.IsNullOrEmpty(TargetFramework) - ? $"{Indentation}{Project} {Target} ({Stopwatch.Elapsed.TotalSeconds:F1}s)" - : $"{Indentation}{Project} [{TargetFramework}] {Target} ({Stopwatch.Elapsed.TotalSeconds:F1}s)"; + ? ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectBuilding_NoTF", + Indentation, + Project, + Target, + duration) + : ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectBuilding_WithTF", + Indentation, + Project, + TargetFramework, + Target, + duration); } } @@ -217,14 +228,12 @@ private void BuildFinished(object sender, BuildFinishedEventArgs e) Terminal.BeginUpdate(); try { + double duration = (e.Timestamp - _buildStartTime).TotalSeconds; Terminal.WriteLine(""); - Terminal.Write("Build "); - - PrintBuildResult(e.Succeeded, _buildHasErrors, _buildHasWarnings); - - double duration = (e.Timestamp - _buildStartTime).TotalSeconds; - Terminal.WriteLine($" in {duration:F1}s"); + Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("BuildFinished", + RenderBuildResult(e.Succeeded, _buildHasErrors, _buildHasWarnings), + duration.ToString("F1"))); } finally { @@ -301,7 +310,8 @@ private void ProjectFinished(object sender, ProjectFinishedEventArgs e) try { EraseNodes(); - Terminal.WriteLine($"Restore complete ({duration:F1}s)"); + Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("RestoreComplete", + duration.ToString("F1"))); DisplayNodes(); } finally @@ -322,30 +332,36 @@ private void ProjectFinished(object sender, ProjectFinishedEventArgs e) { EraseNodes(); - double duration = project.Stopwatch.Elapsed.TotalSeconds; + string duration = project.Stopwatch.Elapsed.TotalSeconds.ToString("F1"); ReadOnlyMemory? outputPath = project.OutputPath; - Terminal.Write(Indentation); - - if (e.ProjectFile is not null) - { - ReadOnlySpan projectFile = Path.GetFileNameWithoutExtension(e.ProjectFile.AsSpan()); - Terminal.Write(projectFile); - Terminal.Write(" "); - } - if (!string.IsNullOrEmpty(project.TargetFramework)) - { - Terminal.Write($"[{project.TargetFramework}] "); - } + string projectFile = e.ProjectFile is not null ? + Path.GetFileNameWithoutExtension(e.ProjectFile) : + string.Empty; - // Print 'failed', 'succeeded with warnings', or 'succeeded' depending on the build result and diagnostic messages + // Build result. One of 'failed', 'succeeded with warnings', or 'succeeded' depending on the build result and diagnostic messages // reported during build. bool haveErrors = project.BuildMessages?.Exists(m => m.Severity == MessageSeverity.Error) == true; bool haveWarnings = project.BuildMessages?.Exists(m => m.Severity == MessageSeverity.Warning) == true; - PrintBuildResult(e.Succeeded, haveErrors, haveWarnings); + string buildResult = RenderBuildResult(e.Succeeded, haveErrors, haveWarnings); - _buildHasErrors |= haveErrors; - _buildHasWarnings |= haveWarnings; + if (string.IsNullOrEmpty(project.TargetFramework)) + { + Terminal.Write(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectFinished_NoTF", + Indentation, + projectFile, + buildResult, + duration)); + } + else + { + Terminal.Write(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectFinished_WithTF", + Indentation, + projectFile, + project.TargetFramework, + buildResult, + duration)); + } // Print the output path as a link if we have it. if (outputPath is not null) @@ -360,15 +376,13 @@ private void ProjectFinished(object sender, ProjectFinishedEventArgs e) { // Ignore any GetDirectoryName exceptions. } -#if NETCOREAPP - Terminal.WriteLine($" ({duration:F1}s) → {AnsiCodes.LinkPrefix}{url}{AnsiCodes.LinkInfix}{outputPath}{AnsiCodes.LinkSuffix}"); -#else - Terminal.WriteLine($" ({duration:F1}s) → {AnsiCodes.LinkPrefix}{url.ToString()}{AnsiCodes.LinkInfix}{outputPath.ToString()}{AnsiCodes.LinkSuffix}"); -#endif + + Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectFinished_OutputPath", + $"{AnsiCodes.LinkPrefix}{url.ToString()}{AnsiCodes.LinkInfix}{outputPath}{AnsiCodes.LinkSuffix}")); } else { - Terminal.WriteLine($" ({duration:F1}s)"); + Terminal.WriteLine(string.Empty); } // Print diagnostic output under the Project -> Output line. @@ -386,6 +400,9 @@ private void ProjectFinished(object sender, ProjectFinishedEventArgs e) } } + _buildHasErrors |= haveErrors; + _buildHasWarnings |= haveWarnings; + DisplayNodes(); } finally @@ -708,26 +725,26 @@ public void Clear() /// True if the build completed with success. /// True if the build has logged at least one error. /// True if the build has logged at least one warning. - private void PrintBuildResult(bool succeeded, bool hasError, bool hasWarning) + private string RenderBuildResult(bool succeeded, bool hasError, bool hasWarning) { if (!succeeded) { // If the build failed, we print one of three red strings. string text = (hasError, hasWarning) switch { - (true, _) => "failed with errors", - (false, true) => "failed with warnings", - _ => "failed", + (true, _) => ResourceUtilities.GetResourceString("BuildResult_FailedWithError"), + (false, true) => ResourceUtilities.GetResourceString("BuildResult_FailedWithWarn"), + _ => ResourceUtilities.GetResourceString("BuildResult_Failed"), }; - Terminal.WriteColor(TerminalColor.Red, text); + return Terminal.RenderColor(TerminalColor.Red, text); } else if (hasWarning) { - Terminal.WriteColor(TerminalColor.Yellow, "succeeded with warnings"); + return Terminal.RenderColor(TerminalColor.Yellow, ResourceUtilities.GetResourceString("BuildResult_SucceededWithWarn")); } else { - Terminal.WriteColor(TerminalColor.Green, "succeeded"); + return Terminal.RenderColor(TerminalColor.Green, ResourceUtilities.GetResourceString("BuildResult_Succeeded")); } } diff --git a/src/MSBuild/LiveLogger/Terminal.cs b/src/MSBuild/LiveLogger/Terminal.cs index 9b187391778..dfdcd21b396 100644 --- a/src/MSBuild/LiveLogger/Terminal.cs +++ b/src/MSBuild/LiveLogger/Terminal.cs @@ -132,10 +132,16 @@ public void WriteColor(TerminalColor color, string text) } else { - Write($"{AnsiCodes.CSI}{(int)color}{AnsiCodes.SetColor}{text}{AnsiCodes.SetDefaultColor}"); + Write(RenderColor(color, text)); } } + /// + public string RenderColor(TerminalColor color, string text) + { + return $"{AnsiCodes.CSI}{(int)color}{AnsiCodes.SetColor}{text}{AnsiCodes.SetDefaultColor}"; + } + /// public void WriteColorLine(TerminalColor color, string text) { diff --git a/src/MSBuild/Resources/Strings.resx b/src/MSBuild/Resources/Strings.resx index 679f83d8d36..4d9924afe1e 100644 --- a/src/MSBuild/Resources/Strings.resx +++ b/src/MSBuild/Resources/Strings.resx @@ -1366,6 +1366,102 @@ The '{0}' switch is not supported for solution files. + + + Restore complete ({0}s) + + Duration in seconds with 1 decimal point is: {0}" + + + + Build {0} in {1}s + + Overall build summary + {0}: BuildResult_X bellow is + {1}: duration in seconds with 1 decimal point + + + + failed with errors + + Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" + + + + failed with warnings + + Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" + + + + failed + + Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" + + + + succeeded + + Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" + + + + succeeded with warnings + + Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" + + + + {0}{1} {2} ({3}s) + + Project finished summary. + {0}: indentation - few spaces to visually indent row + {1}: project name + {2}: BuildResult_{X} + {3}: duration in seconds with 1 decimal point + + + + {0}{1} [2] {3} ({4}s) + + Project finished summary including target framework information. + {0}: indentation - few spaces to visually indent row + {1}: project name + {2}: target framework + {3}: BuildResult_{X} + {4}: duration in seconds with 1 decimal point + + + + → {0} + + Info about project output - when known. Printed after ProjectFinished_NoTF or ProjectFinished_WithTF. + {0}: VT100 coded hyperlink to project output directory + + + + {0}{1} {2} ({3}s) + + Project finished summary. + {0}: indentation - few spaces to visually indent row + {1}: project name + {2}: target + {3}: duration in seconds with 1 decimal point + + + + {0}{1} [2] {3} ({4}s) + + Project finished summary including target framework information. + {0}: indentation - few spaces to visually indent row + {1}: project name + {2}: target framework + {3}: target + {4}: duration in seconds with 1 decimal point + + + +