diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs
index eb4557c04d2..77fbc426357 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs
@@ -111,36 +111,52 @@ internal static void ShowUpdateNotification(PSHostUserInterface hostUI)
? ManagedEntranceStrings.StableUpdateNotificationMessage
: ManagedEntranceStrings.PreviewUpdateNotificationMessage;
- string notificationColor = string.Empty;
- string resetColor = string.Empty;
+ string notificationMsg = FormatUpdateNotification(notificationMsgTemplate, releaseTag, hostUI.SupportsVirtualTerminal);
- string line2Padding = string.Empty;
- string line3Padding = string.Empty;
+ hostUI.WriteLine();
+ hostUI.WriteLine(notificationMsg);
+ }
+ }
- // We calculate how much whitespace we need to make it look nice
- if (hostUI.SupportsVirtualTerminal)
- {
- // Swaps foreground and background colors.
- notificationColor = "\x1B[7m";
- resetColor = "\x1B[0m";
-
- // The first line is longest, if the message changes, this needs to be updated
- int line1Length = notificationMsgTemplate.IndexOf('\n');
- int line2Length = notificationMsgTemplate.IndexOf('\n', line1Length + 1);
- int line3Length = notificationMsgTemplate.IndexOf('\n', line2Length + 1);
- line3Length -= line2Length + 1;
- line2Length -= line1Length + 1;
-
- line2Padding = line2Padding.PadRight(line1Length - line2Length + releaseTag.Length);
- // 3 represents the extra placeholder in the template
- line3Padding = line3Padding.PadRight(line1Length - line3Length + 3);
- }
+ ///
+ /// Formats the update notification message from the given template.
+ ///
+ /// The three-line notification message template.
+ /// The version of the new release.
+ /// Whether to highlight the message and pad the shorter lines to the width of the first line.
+ /// The formatted notification message.
+ internal static string FormatUpdateNotification(string notificationMsgTemplate, string releaseTag, bool supportsVirtualTerminal)
+ {
+ string notificationColor = string.Empty;
+ string resetColor = string.Empty;
- string notificationMsg = string.Format(CultureInfo.CurrentCulture, notificationMsgTemplate, releaseTag, notificationColor, resetColor, line2Padding, line3Padding);
+ string line2Padding = string.Empty;
+ string line3Padding = string.Empty;
- hostUI.WriteLine();
- hostUI.WriteLine(notificationMsg);
+ // We calculate how much whitespace we need to make it look nice
+ if (supportsVirtualTerminal)
+ {
+ // Swaps foreground and background colors.
+ notificationColor = "\x1B[7m";
+ resetColor = "\x1B[0m";
+
+ // The first line is usually the longest, but localized templates may have a longer
+ // second or third line. Clamp the padding so it can't go negative and crash the host
+ // over a cosmetic alignment mismatch.
+ int line1Length = notificationMsgTemplate.IndexOf('\n');
+ int line2Length = notificationMsgTemplate.IndexOf('\n', line1Length + 1);
+ int line3Length = notificationMsgTemplate.IndexOf('\n', line2Length + 1);
+ line3Length -= line2Length + 1;
+ line2Length -= line1Length + 1;
+
+ line2Padding = line2Padding.PadRight(
+ Math.Max(0, line1Length - line2Length + releaseTag.Length));
+ // 3 represents the extra placeholder in the template
+ line3Padding = line3Padding.PadRight(
+ Math.Max(0, line1Length - line3Length + 3));
}
+
+ return string.Format(CultureInfo.CurrentCulture, notificationMsgTemplate, releaseTag, notificationColor, resetColor, line2Padding, line3Padding);
}
internal static async Task CheckForUpdates()
diff --git a/test/xUnit/csharp/UpdatesNotificationTests.cs b/test/xUnit/csharp/UpdatesNotificationTests.cs
new file mode 100644
index 00000000000..3c1f5b49e07
--- /dev/null
+++ b/test/xUnit/csharp/UpdatesNotificationTests.cs
@@ -0,0 +1,84 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Globalization;
+
+using Microsoft.PowerShell;
+using Xunit;
+
+namespace PSTests.Parallel
+{
+ public static class UpdatesNotificationTests
+ {
+ private const string ReleaseTag = "7.6.7";
+
+ private static readonly string[] TemplateNames = new[]
+ {
+ nameof(ManagedEntranceStrings.StableUpdateNotificationMessage),
+ nameof(ManagedEntranceStrings.LTSUpdateNotificationMessage),
+ nameof(ManagedEntranceStrings.PreviewUpdateNotificationMessage),
+ };
+
+ // Keep in sync with the localized resources under src/Microsoft.PowerShell.ConsoleHost/resources.
+ private static readonly string[] LocalizedCultures = new[]
+ {
+ "cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-BR", "ru", "tr", "zh-Hans", "zh-Hant",
+ };
+
+ public static IEnumerable