Skip to content

Commit

Permalink
Fix localizability issues in Windows Terminal (#5339)
Browse files Browse the repository at this point in the history
Loc issues are given to us through the internal bug tracker.

* Lock some strings, or parts of strings, that should not be localized.
* Switch to positional format parameters
* Remove the forced newlines in the warning resources; insert them at
  runtime

Fixes MSFT:25936156.
  • Loading branch information
DHowett authored Apr 14, 2020
1 parent 348f468 commit 37e62da
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 46 deletions.
4 changes: 4 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,19 +339,22 @@ namespace winrt::TerminalApp::implementation
const auto errorLabel = GetLibraryResourceString(contentKey);
errorRun.Text(errorLabel);
warningsTextBlock.Inlines().Append(errorRun);
warningsTextBlock.Inlines().Append(Documents::LineBreak{});

if (FAILED(settingsLoadedResult))
{
if (!_settingsLoadExceptionText.empty())
{
warningsTextBlock.Inlines().Append(_BuildErrorRun(_settingsLoadExceptionText, ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Resources()));
warningsTextBlock.Inlines().Append(Documents::LineBreak{});
}
}

// Add a note that we're using the default settings in this case.
winrt::Windows::UI::Xaml::Documents::Run usingDefaultsRun;
const auto usingDefaultsText = RS_(L"UsingDefaultSettingsText");
usingDefaultsRun.Text(usingDefaultsText);
warningsTextBlock.Inlines().Append(Documents::LineBreak{});
warningsTextBlock.Inlines().Append(usingDefaultsRun);

Controls::ContentDialog dialog;
Expand Down Expand Up @@ -388,6 +391,7 @@ namespace winrt::TerminalApp::implementation
if (!warningText.empty())
{
warningsTextBlock.Inlines().Append(_BuildErrorRun(warningText, ::winrt::Windows::UI::Xaml::Application::Current().as<::winrt::TerminalApp::App>().Resources()));
warningsTextBlock.Inlines().Append(Documents::LineBreak{});
}
}

Expand Down
48 changes: 22 additions & 26 deletions src/cascadia/TerminalApp/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -118,37 +118,30 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="InitialJsonParseErrorText" xml:space="preserve">
<value>Settings could not be loaded from file. Check for syntax errors, including trailing commas.
</value>
<value>Settings could not be loaded from file. Check for syntax errors, including trailing commas.</value>
</data>
<data name="MissingDefaultProfileText" xml:space="preserve">
<value>Could not find your default profile in your list of profiles - using the first profile. Check to make sure the defaultProfile matches the GUID of one of your profiles.
</value>
<value>Could not find your default profile in your list of profiles - using the first profile. Check to make sure the "defaultProfile" matches the GUID of one of your profiles.</value>
<comment>{Locked="\"defaultProfile\""}</comment>
</data>
<data name="DuplicateProfileText" xml:space="preserve">
<value>Found multiple profiles with the same GUID in your settings file - ignoring duplicates. Make sure each profile's GUID is unique.
</value>
<value>Found multiple profiles with the same GUID in your settings file - ignoring duplicates. Make sure each profile's GUID is unique.</value>
</data>
<data name="UnknownColorSchemeText" xml:space="preserve">
<value>Found a profile with an invalid "colorScheme". Defaulting that profile to the default colors. Make sure that when setting a "colorScheme", the value matches the "name" of a color scheme in the "schemes" list.
</value>
<value>Found a profile with an invalid "colorScheme". Defaulting that profile to the default colors. Make sure that when setting a "colorScheme", the value matches the "name" of a color scheme in the "schemes" list.</value>
<comment>{Locked="\"colorScheme\"","\"name\"","\"schemes\""}</comment>
</data>
<data name="NoProfilesText" xml:space="preserve">
<value>No profiles were found in your settings.
</value>
<value>No profiles were found in your settings.</value>
</data>
<data name="AllProfilesHiddenText" xml:space="preserve">
<value>All profiles were hidden in your settings. You must have at least one non-hidden profile.
</value>
<value>All profiles were hidden in your settings. You must have at least one non-hidden profile.</value>
</data>
<data name="ReloadJsonParseErrorText" xml:space="preserve">
<value>Settings could not be reloaded from file. Check for syntax errors, including trailing commas.
</value>
<value>Settings could not be reloaded from file. Check for syntax errors, including trailing commas.</value>
</data>
<data name="UsingDefaultSettingsText" xml:space="preserve">
<value>
Temporarily using the Windows Terminal default settings.
</value>
<value>Temporarily using the Windows Terminal default settings.</value>
</data>
<data name="InitialJsonParseErrorTitle" xml:space="preserve">
<value>Failed to load settings</value>
Expand All @@ -164,6 +157,7 @@ Temporarily using the Windows Terminal default settings.
</data>
<data name="FeedbackUriValue" xml:space="preserve">
<value>https://go.microsoft.com/fwlink/?linkid=2125419</value>
<comment>{Locked}This is a FWLink, so it will be localized with the fwlink tool</comment>
</data>
<data name="AboutMenuItem" xml:space="preserve">
<value>About</value>
Expand All @@ -176,21 +170,22 @@ Temporarily using the Windows Terminal default settings.
</data>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Found a profile with an invalid "backgroundImage". Defaulting that profile to have no background image. Make sure that when setting a "backgroundImage", the value is a valid file path to an image.</value>
<comment>{Locked="\"backgroundImage\""}</comment>
</data>
<data name="InvalidIcon" xml:space="preserve">
<value>Found a profile with an invalid "icon". Defaulting that profile to have no icon. Make sure that when setting an "icon", the value is a valid file path to an image.</value>
<comment>{Locked="\"icon\""} The word "icon" in quotes is locked, the word icon OUTSIDE of quotes should be localized.</comment>
</data>
<data name="AtLeastOneKeybindingWarning" xml:space="preserve">
<value>Warnings were found while parsing your keybindings:
</value>
<value>Warnings were found while parsing your keybindings:</value>
</data>
<data name="TooManyKeysForChord" xml:space="preserve">
<value> Found a keybinding with too many strings for the "keys" array. There should only be one string value in the "keys" array.
</value>
<value>&#x2022; Found a keybinding with too many strings for the "keys" array. There should only be one string value in the "keys" array.</value>
<comment>{Locked="\"keys\"","&#x2022;"} This glyph is a bullet, used in a bulleted list.</comment>
</data>
<data name="MissingRequiredParameter" xml:space="preserve">
<value> Found a keybinding that was missing a required parameter value. This keybinding will be ignored.
</value>
<value>&#x2022; Found a keybinding that was missing a required parameter value. This keybinding will be ignored.</value>
<comment>{Locked="&#x2022;"} This glyph is a bullet, used in a bulleted list.</comment>
</data>
<data name="CmdCommandArgDesc" xml:space="preserve">
<value>An optional command, with arguments, to be spawned in the new tab or pane</value>
Expand All @@ -211,7 +206,7 @@ Temporarily using the Windows Terminal default settings.
<value>Create a new tab</value>
</data>
<data name="CmdProfileArgDesc" xml:space="preserve">
<value>Open with the given profile. Accepts either the name or guid of a profile</value>
<value>Open with the given profile. Accepts either the name or GUID of a profile</value>
</data>
<data name="CmdSplitPaneDesc" xml:space="preserve">
<value>Create a new split pane</value>
Expand All @@ -223,7 +218,8 @@ Temporarily using the Windows Terminal default settings.
<value>Create the new pane as a vertical split (think [|])</value>
</data>
<data name="CmdStartingDirArgDesc" xml:space="preserve">
<value>Open in the given directory instead of the profile's set startingDirectory</value>
<value>Open in the given directory instead of the profile's set "startingDirectory"</value>
<comment>{Locked="\"startingDirectory\""}</comment>
</data>
<data name="NewTabSplitButton.[using:Windows.UI.Xaml.Automation]AutomationProperties.HelpText" xml:space="preserve">
<value>Press the button to open a new terminal tab with your default profile. Open the flyout to select which profile you want to open.</value>
Expand Down Expand Up @@ -287,4 +283,4 @@ Temporarily using the Windows Terminal default settings.
<value>Command Prompt</value>
<comment>This is the name of "Command Prompt", as localized in Windows. The localization here should match the one in the Windows product for "Command Prompt"</comment>
</data>
</root>
</root>
6 changes: 3 additions & 3 deletions src/cascadia/TerminalConnection/AzureConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static constexpr int USER_INFO_COLOR = 97; // white - the color of clarifying in

static inline std::wstring _colorize(const unsigned int colorCode, const std::wstring_view text)
{
return wil::str_printf<std::wstring>(L"\x1b[%um%.*s\x1b[m", colorCode, gsl::narrow_cast<size_t>(text.size()), text.data());
return fmt::format(L"\x1b[{0}m{1}\x1b[m", colorCode, text);
}

// Takes N resource names, loads the first one as a format string, and then
Expand All @@ -57,12 +57,12 @@ static inline std::wstring _colorize(const unsigned int colorCode, const std::ws
template<typename... Args>
static inline std::wstring _formatResWithColoredUserInputOptions(const std::wstring_view resourceKey, Args&&... args)
{
return wil::str_printf<std::wstring>(GetLibraryResourceString(resourceKey).data(), (_colorize(USER_INPUT_COLOR, GetLibraryResourceString(args)).data())...);
return fmt::format(std::wstring_view{ GetLibraryResourceString(resourceKey) }, (_colorize(USER_INPUT_COLOR, GetLibraryResourceString(args)))...);
}

static inline std::wstring _formatTenantLine(int tenantNumber, const std::wstring_view tenantName, const std::wstring_view tenantID)
{
return wil::str_printf<std::wstring>(RS_(L"AzureIthTenant").data(), _colorize(USER_INPUT_COLOR, std::to_wstring(tenantNumber)).data(), _colorize(USER_INFO_COLOR, tenantName).data(), tenantID.data());
return fmt::format(std::wstring_view{ RS_(L"AzureIthTenant") }, _colorize(USER_INPUT_COLOR, std::to_wstring(tenantNumber)), _colorize(USER_INFO_COLOR, tenantName), tenantID);
}

namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/TerminalConnection/ConptyConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// EXIT POINT
const auto hr = wil::ResultFromCaughtException();

winrt::hstring failureText{ wil::str_printf<std::wstring>(RS_(L"ProcessFailedToLaunch").c_str(), gsl::narrow_cast<unsigned int>(hr), _commandline.c_str()) };
winrt::hstring failureText{ fmt::format(std::wstring_view{ RS_(L"ProcessFailedToLaunch") }, gsl::narrow_cast<unsigned long>(hr), _commandline) };
_TerminalOutputHandlers(failureText);
_transitionToState(ConnectionState::Failed);

Expand All @@ -262,7 +262,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
try
{
winrt::hstring exitText{ wil::str_printf<std::wstring>(RS_(L"ProcessExited").c_str(), status) };
winrt::hstring exitText{ fmt::format(std::wstring_view{ RS_(L"ProcessExited") }, status) };
_TerminalOutputHandlers(L"\r\n");
_TerminalOutputHandlers(exitText);
}
Expand Down
37 changes: 22 additions & 15 deletions src/cascadia/TerminalConnection/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,16 @@
<value>Please enter the desired tenant number.</value>
</data>
<data name="AzureNewLogin" xml:space="default">
<value>Enter %s to login with a different account</value>
<value>Enter {0} to login with a new account</value>
<comment>{0} will be replaced with the resource from AzureUserEntry_NewLogin; it is intended to be a single-character shorthand for "new account"</comment>
</data>
<data name="AzureRemoveStored" xml:space="default">
<value>Enter %s to remove the above saved connection settings.</value>
<value>Enter {0} to remove the above saved connection settings.</value>
<comment>{0} will be replaced with the resource from AzureUserEntry_RemoveStored; it is intended to be a single-character shorthand for "remove stored"</comment>
</data>
<data name="AzureInvalidAccessInput" xml:space="default">
<value>Please enter a valid number to access the stored connection settings, %s to make a new one, or %s to remove the stored ones.</value>
<value>Please enter a valid number to access the stored connection settings, {0} to log in with a new account, or {1} to remove the saved connection settings.</value>
<comment>{0} will be replaced with the resource from AzureUserEntry_NewLogin, and {1} will be replaced with AzureUserEntry_RemoveStored. This is an error message, used after AzureNewLogin/AzureRemoveStored if the user enters an invalid value.</comment>
</data>
<data name="AzureNonNumberError" xml:space="preserve">
<value>Please enter a number.</value>
Expand All @@ -143,12 +146,15 @@
</data>
<data name="AzureNoCloudAccount" xml:space="preserve">
<value>You have not set up your cloud shell account yet. Please go to https://shell.azure.com to set it up.</value>
<comment>{Locked="https://shell.azure.com"} This URL should not be localized. Everything else should.</comment>
</data>
<data name="AzureStorePrompt" xml:space="default">
<value>Do you want to save these connection settings for future logins? [%s/%s]</value>
<value>Do you want to save these connection settings for future logins? [{0}/{1}]</value>
<comment>{0} and {1} will be replaced with AzureUserEntry_Yes and AzureUserEntry_No. They are single-character shorthands for "yes" and "no" in this language.</comment>
</data>
<data name="AzureInvalidStoreInput" xml:space="default">
<value>Please enter %s or %s</value>
<value>Please enter {0} or {1}</value>
<comment>{0} and {1} will be replaced with AzureUserEntry_Yes and AzureUserEntry_No. This resource will be used as an error response after AzureStorePrompt.</comment>
</data>
<data name="AzureRequestingCloud" xml:space="preserve">
<value>Requesting a cloud shell instance...</value>
Expand Down Expand Up @@ -184,35 +190,36 @@
<value>&lt;unknown tenant name&gt;</value>
</data>
<data name="AzureIthTenant" xml:space="default">
<value>Tenant %s: %s (%s)</value>
<value>Tenant {0}: {1} ({2})</value>
<comment>{0} is the tenant's number, which the user will enter to connect to the tenant. {1} is the tenant's display name, which will be meaningful for the user. {2} is the tenant's internal ID number.</comment>
</data>
<data name="AzureSuccessfullyAuthenticated" xml:space="preserve">
<value>Authenticated.</value>
</data>
<data name="AzureUserEntry_NewLogin" xml:space="preserve">
<value>n</value>
<comment>The user must enter this character to say NEW LOGIN (AzureInvalidAccessInput, AzureNewLogin)</comment>
<comment>This is shorthand for "new login". The user must enter this character to activate the New Login feature (AzureInvalidAccessInput, AzureNewLogin)</comment>
</data>
<data name="AzureUserEntry_RemoveStored" xml:space="preserve">
<value>r</value>
<comment>The user must enter this character to say REMOVE SAVED LOGINS (AzureRemoveStored, AzureInvalidAccessInput)</comment>
<comment>This is shorthand for "remove saved connections". The user must enter this character to activate the Remove Saved Logins feature (AzureRemoveStored, AzureInvalidAccessInput)</comment>
</data>
<data name="AzureUserEntry_Yes" xml:space="preserve">
<value>y</value>
<comment>The user must enter this character to signify YES</comment>
<comment>This is shorthand for "yes". The user must enter this character to CONFIRM a prompt.</comment>
</data>
<data name="AzureUserEntry_No" xml:space="preserve">
<value>n</value>
<comment>The user must enter this character to signify NO</comment>
<comment>This is shorthand for "no". The user must enter this character to DECLINE a prompt.</comment>
</data>
<data name="ProcessExited" xml:space="preserve">
<value>[process exited with code %u]</value>
<comment>The first argument (%u) is the (positive) error code of the process. 0 is success.</comment>
<value>[process exited with code {0}]</value>
<comment>The first argument {0} is the (positive) error code of the process. When there is no error, the number ZERO will be displayed.</comment>
</data>
<data name="ProcessFailedToLaunch" xml:space="preserve">
<value>[error 0x%8.08x when launching `%ls']</value>
<comment>The first argument is the hexadecimal error code. The second is the process name.
If this resource spans multiple lines, it will not be displayed properly. Yeah.</comment>
<value>[error {0:#08x} when launching `{1}']</value>
<comment>The first argument {0...} is the hexadecimal error code. The second argument {1} is the user-specified path to a program.
If this string is broken to multiple lines, it will not be displayed properly.</comment>
</data>
<data name="TelnetInternetOrServerIssue" xml:space="preserve">
<value>Could not connect to telnet server.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
</data>
<data name="SearchBox_Close.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Close Search Box</value>
<comment>The explanation of the search box close button used by Narrator and other screen readers.</comment>
</data>
<data name="TermControl_RendererFailedTextBlock.Text" xml:space="preserve">
<value>This terminal has encountered an issue with the graphics driver and it could not recover in time. It has been suspended.</value>
Expand Down

0 comments on commit 37e62da

Please sign in to comment.