-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[LiveLogger ] Localize strings #8682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -42,9 +42,20 @@ internal record NodeStatus(string Project, string? TargetFramework, string Targe | |||
| { | ||||
| public override string ToString() | ||||
| { | ||||
| string duration = Stopwatch.Elapsed.TotalSeconds.ToString("F1"); | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the double -> string formatting locale-aware if done in code like this? My suggestion is to omit the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you. I guess I could argue either way - for the app logic to own the formatting so it's easier to change in the future and for the resource files to contain it so it can be localized. FWIW, we already have a precedence where the format is specified in .resx and it's translated to the same format in all languages. So it probably doesn't matter. msbuild/src/Build/Resources/Strings.resx Line 1481 in c6e6cd4
|
||||
|
|
||||
| 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", | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking about ways we could combine these into one ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword call...I'm tempted to propose rearranging the arguments to put TF at the end, so we can always pass it even if it's null or empty but not necessarily display it or even having a custom part in the middle of the string, but I'm not convinced either change is actually better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I though about that. I even have it coded as subpart but the code, IMO, was harder to read and translation was more confusing. It can be changed easily though, if we decide to do so. |
||||
| 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<char>? outputPath = project.OutputPath; | ||||
|
|
||||
| Terminal.Write(Indentation); | ||||
|
|
||||
| if (e.ProjectFile is not null) | ||||
| { | ||||
| ReadOnlySpan<char> 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() | |||
| /// <param name="succeeded">True if the build completed with success.</param> | ||||
| /// <param name="hasError">True if the build has logged at least one error.</param> | ||||
| /// <param name="hasWarning">True if the build has logged at least one warning.</param> | ||||
| 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")); | ||||
| } | ||||
| } | ||||
|
|
||||
|
|
||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1366,6 +1366,102 @@ | |||||
| <data name="UnsupportedSwitchForSolutionFiles" Visibility="Public"> | ||||||
| <value>The '{0}' switch is not supported for solution files.</value> | ||||||
| </data> | ||||||
| <!-- **** LiveLogger strings begin **** --> | ||||||
| <data name="RestoreComplete" xml:space="preserve"> | ||||||
| <value>Restore complete ({0}s)</value> | ||||||
| <comment> | ||||||
| Duration in seconds with 1 decimal point is: {0}" | ||||||
rokonec marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="BuildFinished" xml:space="preserve"> | ||||||
| <value>Build {0} in {1}s</value> | ||||||
| <comment> | ||||||
| Overall build summary | ||||||
| {0}: BuildResult_X bellow is | ||||||
rokonec marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| {1}: duration in seconds with 1 decimal point | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="BuildResult_FailedWithError" xml:space="preserve"> | ||||||
rokonec marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| <value>failed with errors</value> | ||||||
| <comment> | ||||||
| Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="BuildResult_FailedWithWarn" xml:space="preserve"> | ||||||
rokonec marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| <value>failed with warnings</value> | ||||||
| <comment> | ||||||
| Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="BuildResult_Failed" xml:space="preserve"> | ||||||
| <value>failed</value> | ||||||
| <comment> | ||||||
| Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="BuildResult_Succeeded" xml:space="preserve"> | ||||||
| <value>succeeded</value> | ||||||
| <comment> | ||||||
| Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="BuildResult_SucceededWithWarn" xml:space="preserve"> | ||||||
rokonec marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| <value>succeeded with warnings</value> | ||||||
| <comment> | ||||||
| Part of Live Logger summary message: "Build {BuildResult_X} in {duration}s" | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="ProjectFinished_NoTF" xml:space="preserve"> | ||||||
| <value>{0}{1} {2} ({3}s)</value> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
? (If so, then also below) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intent of this PR was to make Live Logger localizable while keeping it exactly like it was. |
||||||
| <comment> | ||||||
| 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 | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="ProjectFinished_WithTF" xml:space="preserve"> | ||||||
| <value>{0}{1} [2] {3} ({4}s)</value> | ||||||
| <comment> | ||||||
| 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 | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="ProjectFinished_OutputPath" xml:space="preserve"> | ||||||
| <value> → {0}</value> | ||||||
| <comment> | ||||||
| Info about project output - when known. Printed after ProjectFinished_NoTF or ProjectFinished_WithTF. | ||||||
| {0}: VT100 coded hyperlink to project output directory | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="ProjectBuilding_NoTF" xml:space="preserve"> | ||||||
| <value>{0}{1} {2} ({3}s)</value> | ||||||
| <comment> | ||||||
| Project finished summary. | ||||||
| {0}: indentation - few spaces to visually indent row | ||||||
| {1}: project name | ||||||
| {2}: target | ||||||
| {3}: duration in seconds with 1 decimal point | ||||||
| </comment> | ||||||
| </data> | ||||||
| <data name="ProjectBuilding_WithTF" xml:space="preserve"> | ||||||
| <value>{0}{1} [2] {3} ({4}s)</value> | ||||||
| <comment> | ||||||
| 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 | ||||||
| </comment> | ||||||
| </data> | ||||||
|
Comment on lines
+1414
to
+1462
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think there's a chance non-English versions of these strings will look differently other than the seconds unit abbreviation? I wonder if we can have only one localized string There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I see it not likely. However, I am not expert in localization. It could be that theoretically some languages might not use spaces, other languages might despise brackets, some languages prefer different order of data presenting so they can prefer target before of project like I'd rather play safe here... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The changes you're describing don't look like something that would be done as part of translation. Maybe there are RTL considerations, not sure. Not blocking but I'd like to ask our loc champion. @richaverma1 can you please provide guidance? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have checked in past and none supported languages in MSBuild is, AFAIK, RTL. |
||||||
| <!-- **** LiveLogger strings end **** --> | ||||||
|
|
||||||
| <!-- | ||||||
| The command line message bucket is: MSB1001 - MSB1999 | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
We're currently displaying hundredths of a second in the not-live logger, but it seems like we switched to tenths of a second for the live logger. Was that an intentional choice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is consistent in new LiveLogger, so I believe it is intentional. IMO, from practical point, tenths are just enough.