diff --git a/installer/PowerToysBootstrapper/bootstrapper/Resources.resx b/installer/PowerToysBootstrapper/bootstrapper/Resources.resx index d1ca376f1a..e80ed5a84a 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/Resources.resx +++ b/installer/PowerToysBootstrapper/bootstrapper/Resources.resx @@ -64,4 +64,94 @@ PowerToys installation error + + An update to PowerToys is available. + + + PowerToys download started. + + + An update to PowerToys is ready to install. + + + Error: couldn't download PowerToys installer. Visit our GitHub page to update. + + + Update now + + + At next launch + + + Error: please uninstall the previous version of PowerToys manually. + + + An update to PowerToys is available. Visit our GitHub page to update. + + + PowerToys is up to date. + + + Visit + + + More info... + + + Abort + + + Click Snooze to be reminded in: + + + 1 day + + + 5 days + + + Downloading... + + + Download complete + + + PowerToys Update + + + We've detected a previous installation of PowerToys. Would you like to remove it? + + + PowerToys: uninstall previous version? + + + Couldn't extract MSI installer! + + + Extracting PowerToys MSI... + + + Uninstalling previous PowerToys version... + + + Couldn't uninstall previous PowerToys version! + + + Installing dotnet... + + + Couldn't install dotnet! + + + Installing new PowerToys version... + + + PowerToys installation complete! + + + Couldn't install new PowerToys version. + + + Snooze + \ No newline at end of file diff --git a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp index 2ab0c29cd5..85774cc741 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp +++ b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp @@ -14,11 +14,14 @@ extern "C" IMAGE_DOS_HEADER __ImageBase; +auto Strings = updating::notifications::strings::create(); + #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) -namespace +namespace // Strings in this namespace should not be localized { const wchar_t APPLICATION_ID[] = L"PowerToysInstaller"; + const wchar_t INSTALLATION_TOAST_TITLE[] = L"PowerToys Installation"; const wchar_t TOAST_TAG[] = L"PowerToysInstallerProgress"; const char LOG_FILENAME[] = "powertoys-bootstrapper-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log"; const char MSI_LOG_FILENAME[] = "powertoys-bootstrapper-msi-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log"; @@ -27,20 +30,6 @@ namespace #undef STR #undef STR_HELPER -namespace localized_strings -{ - const wchar_t INSTALLER_EXTRACT_ERROR[] = L"Couldn't extract MSI installer!"; - const wchar_t TOAST_TITLE[] = L"PowerToys Installation"; - const wchar_t EXTRACTING_INSTALLER[] = L"Extracting PowerToys MSI..."; - const wchar_t UNINSTALLING_PREVIOUS_VERSION[] = L"Uninstalling previous PowerToys version..."; - const wchar_t UNINSTALL_PREVIOUS_VERSION_ERROR[] = L"Couldn't uninstall previous PowerToys version!"; - const wchar_t INSTALLING_DOTNET[] = L"Installing dotnet..."; - const wchar_t DOTNET_INSTALL_ERROR[] = L"Couldn't install dotnet!"; - const wchar_t INSTALLING_NEW_VERSION[] = L"Installing new PowerToys version..."; - const wchar_t NEW_VERSION_INSTALLATION_DONE[] = L"PowerToys installation complete!"; - const wchar_t NEW_VERSION_INSTALLATION_ERROR[] = L"Couldn't install new PowerToys version."; -} - namespace fs = std::filesystem; std::optional extractEmbeddedInstaller() @@ -96,7 +85,6 @@ void setup_log(fs::path directory, const spdlog::level::level_enum severity) int bootstrapper() { - using namespace localized_strings; winrt::init_apartment(); cxxopts::Options options{ "PowerToysBootstrapper" }; // clang-format off @@ -252,7 +240,7 @@ int bootstrapper() iconPath = std::move(*extractedIcon); } spdlog::debug("Registering app id for toast notifications"); - notifications::register_application_id(TOAST_TITLE, iconPath.c_str()); + notifications::register_application_id(INSTALLATION_TOAST_TITLE, iconPath.c_str()); auto removeShortcut = wil::scope_exit([&] { notifications::unregister_application_id(); @@ -274,12 +262,12 @@ int bootstrapper() std::mutex progressLock; notifications::progress_bar_params progressParams; progressParams.progress = 0.0f; - progressParams.progress_title = EXTRACTING_INSTALLER; + progressParams.progress_title = GET_RESOURCE_STRING(IDS_EXTRACTING_INSTALLER); notifications::toast_params params{ TOAST_TAG, false, std::move(progressParams) }; if (!silent) { spdlog::debug("Launching progress toast notification"); - notifications::show_toast_with_activations({}, TOAST_TITLE, {}, {}, std::move(params)); + notifications::show_toast_with_activations({}, INSTALLATION_TOAST_TITLE, {}, {}, std::move(params)); } auto processToasts = wil::scope_exit([&] { @@ -322,7 +310,7 @@ int bootstrapper() { if (!silent) { - notifications::show_toast(INSTALLER_EXTRACT_ERROR, TOAST_TITLE); + notifications::show_toast(GET_RESOURCE_STRING(IDS_INSTALLER_EXTRACT_ERROR), INSTALLATION_TOAST_TITLE); } spdlog::error("Couldn't install the MSI installer ({})", GetLastError()); return 1; @@ -332,7 +320,7 @@ int bootstrapper() fs::remove(*installerPath, _); }); - updateProgressBar(.25f, UNINSTALLING_PREVIOUS_VERSION); + updateProgressBar(.25f, GET_RESOURCE_STRING(IDS_UNINSTALLING_PREVIOUS_VERSION).c_str()); spdlog::debug("Acquiring existing MSI package path"); const auto package_path = updating::get_msi_package_path(); if (!package_path.empty()) @@ -343,15 +331,15 @@ int bootstrapper() { spdlog::debug("Existing MSI package path not found"); } - if (!package_path.empty() && !updating::uninstall_msi_version(package_path) && !silent) + if (!package_path.empty() && !updating::uninstall_msi_version(package_path, Strings) && !silent) { spdlog::error("Couldn't install the existing MSI package ({})", GetLastError()); - notifications::show_toast(UNINSTALL_PREVIOUS_VERSION_ERROR, TOAST_TITLE); + notifications::show_toast(GET_RESOURCE_STRING(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR), INSTALLATION_TOAST_TITLE); } const bool installDotnet = !skipDotnetInstall; if (installDotnet) { - updateProgressBar(.5f, INSTALLING_DOTNET); + updateProgressBar(.5f, GET_RESOURCE_STRING(IDS_INSTALLING_DOTNET).c_str()); } try @@ -365,7 +353,7 @@ int bootstrapper() !updating::install_dotnet(silent) && !silent) { - notifications::show_toast(DOTNET_INSTALL_ERROR, TOAST_TITLE); + notifications::show_toast(GET_RESOURCE_STRING(IDS_DOTNET_INSTALL_ERROR), INSTALLATION_TOAST_TITLE); } } } @@ -375,13 +363,14 @@ int bootstrapper() MessageBoxW(nullptr, L".NET Core installation", L"Unknown exception encountered!", MB_OK | MB_ICONERROR); } - updateProgressBar(.75f, INSTALLING_NEW_VERSION); + updateProgressBar(.75f, GET_RESOURCE_STRING(IDS_INSTALLING_NEW_VERSION).c_str()); // Always skip dotnet install, because we should've installed it from here earlier std::wstring msiProps = L"SKIPDOTNETINSTALL=1 "; spdlog::debug("Launching MSI installation for new package {}", installerPath->string()); const bool installationDone = MsiInstallProductW(installerPath->c_str(), msiProps.c_str()) == ERROR_SUCCESS; - updateProgressBar(1.f, installationDone ? NEW_VERSION_INSTALLATION_DONE : NEW_VERSION_INSTALLATION_ERROR); + updateProgressBar(1.f, + installationDone ? GET_RESOURCE_STRING(IDS_NEW_VERSION_INSTALLATION_DONE).c_str() : GET_RESOURCE_STRING(IDS_NEW_VERSION_INSTALLATION_ERROR).c_str()); if (!installationDone) { spdlog::error("Couldn't install new MSI package ({})", GetLastError()); diff --git a/src/action_runner/Resources.resx b/src/action_runner/Resources.resx index d1ca376f1a..1b90cd3d36 100644 --- a/src/action_runner/Resources.resx +++ b/src/action_runner/Resources.resx @@ -64,4 +64,67 @@ PowerToys installation error + + An update to PowerToys is available. + + + PowerToys download started. + + + An update to PowerToys is ready to install. + + + Error: couldn't download PowerToys installer. Visit our GitHub page to update. + + + Update now + + + At next launch + + + Error: please uninstall the previous version of PowerToys manually. + + + An update to PowerToys is available. Visit our GitHub page to update. + + + PowerToys is up to date. + + + Visit + + + More info... + + + Abort + + + Click Snooze to be reminded in: + + + 1 day + + + 5 days + + + Downloading... + + + Download complete + + + PowerToys Update + + + We've detected a previous installation of PowerToys. Would you like to remove it? + + + PowerToys: uninstall previous version? + + + Snooze + \ No newline at end of file diff --git a/src/action_runner/action_runner.cpp b/src/action_runner/action_runner.cpp index acabf8d767..321be922b2 100644 --- a/src/action_runner/action_runner.cpp +++ b/src/action_runner/action_runner.cpp @@ -1,4 +1,6 @@ #define WIN32_LEAN_AND_MEAN +#include "Generated Files/resource.h" + #include #include @@ -16,10 +18,10 @@ #include "../runner/tray_icon.h" #include "../runner/action_runner_utils.h" -#include "Generated Files/resource.h" - extern "C" IMAGE_DOS_HEADER __ImageBase; +auto Strings = updating::notifications::strings::create(); + int uninstall_msi_action() { const auto package_path = updating::get_msi_package_path(); @@ -27,7 +29,7 @@ int uninstall_msi_action() { return 0; } - if (!updating::uninstall_msi_version(package_path)) + if (!updating::uninstall_msi_version(package_path, Strings)) { return -1; } diff --git a/src/common/common.cpp b/src/common/common.cpp index 8d9d251e72..2c7d3e919d 100644 --- a/src/common/common.cpp +++ b/src/common/common.cpp @@ -85,22 +85,22 @@ std::optional get_last_error_message(const DWORD dw) return message; } -void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle) +void show_last_error_message(LPCWSTR functionName, DWORD dw, LPCWSTR errorTitle) { const auto system_message = get_last_error_message(dw); if (!system_message.has_value()) { return; } - LPWSTR lpDisplayBuf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (system_message->size() + lstrlenW(lpszFunction) + 40) * sizeof(WCHAR)); + LPWSTR lpDisplayBuf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (system_message->size() + lstrlenW(functionName) + 40) * sizeof(WCHAR)); if (lpDisplayBuf != NULL) { StringCchPrintfW(lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(WCHAR), - localized_strings::LAST_ERROR_FORMAT_STRING, - lpszFunction, - dw, - system_message->c_str()); + L"%s: %s (%d)", + functionName, + system_message->c_str(), + dw); MessageBoxW(NULL, (LPCTSTR)lpDisplayBuf, errorTitle, MB_OK | MB_ICONERROR); LocalFree(lpDisplayBuf); } diff --git a/src/common/common.h b/src/common/common.h index e826702a7b..ed3db9e0a4 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -7,12 +7,6 @@ #include -namespace localized_strings -{ - const wchar_t LAST_ERROR_FORMAT_STRING[] = L"%s failed with error %d: %s"; - const wchar_t LAST_ERROR_TITLE_STRING[] = L"Error"; -} - // Gets position of given window. std::optional get_window_pos(HWND hwnd); @@ -23,7 +17,7 @@ bool is_system_window(HWND hwnd, const char* class_name); int run_message_loop(const bool until_idle = false, const std::optional timeout_seconds = {}); std::optional get_last_error_message(const DWORD dw); -void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle = localized_strings::LAST_ERROR_TITLE_STRING); +void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle); enum WindowState { diff --git a/src/common/notifications.cpp b/src/common/notifications.cpp index f87064b4cd..bb48d76feb 100644 --- a/src/common/notifications.cpp +++ b/src/common/notifications.cpp @@ -33,8 +33,7 @@ using winrt::Windows::UI::Notifications::ToastNotificationManager; namespace fs = std::filesystem; -// This namespace contains strings that SHOULD NOT be localized -namespace +namespace // Strings in this namespace should not be localized { constexpr std::wstring_view TASK_NAME = L"PowerToysBackgroundNotificationsHandler"; constexpr std::wstring_view TASK_ENTRYPOINT = L"PowerToysNotifications.BackgroundHandler"; @@ -45,11 +44,6 @@ namespace constexpr std::wstring_view DEFAULT_TOAST_GROUP = L"PowerToysToastTag"; } -namespace localized_strings -{ - constexpr std::wstring_view SNOOZE_BUTTON = L"Snooze"; -} - static DWORD loop_thread_id() { static const DWORD thread_id = GetCurrentThreadId(); @@ -365,7 +359,7 @@ void notifications::show_toast_with_activations(std::wstring message, toast_xml += '"'; } toast_xml += LR"( content=")"; - toast_xml += localized_strings::SNOOZE_BUTTON; + toast_xml += b.snooze_button_title; toast_xml += LR"(" />)"; } }, actions[i]); diff --git a/src/common/notifications.h b/src/common/notifications.h index ac52539b4f..01a0a986e0 100644 --- a/src/common/notifications.h +++ b/src/common/notifications.h @@ -28,6 +28,7 @@ namespace notifications { std::wstring snooze_title; std::vector durations; + std::wstring snooze_button_title; }; struct link_button @@ -45,7 +46,7 @@ namespace notifications struct progress_bar_params { - std::wstring_view progress_title; + std::wstring progress_title; float progress = 0.f; }; diff --git a/src/common/updating/notifications.cpp b/src/common/updating/notifications.cpp index 8984df265f..01e523e657 100644 --- a/src/common/updating/notifications.cpp +++ b/src/common/updating/notifications.cpp @@ -9,39 +9,10 @@ #include "VersionHelper.h" #include "version.h" -namespace -{ - const wchar_t TOAST_TITLE[] = L"PowerToys Update"; -} - -namespace localized_strings -{ - const wchar_t GITHUB_NEW_VERSION_AVAILABLE[] = L"An update to PowerToys is available.\n"; - const wchar_t GITHUB_NEW_VERSION_DOWNLOAD_STARTED[] = L"PowerToys download started.\n"; - const wchar_t GITHUB_NEW_VERSION_READY_TO_INSTALL[] = L"An update to PowerToys is ready to install.\n"; - const wchar_t GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR[] = L"Error: couldn't download PowerToys installer. Visit our GitHub page to update.\n"; - const wchar_t GITHUB_NEW_VERSION_UPDATE_NOW[] = L"Update now"; - const wchar_t GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART[] = L"At next launch"; - - const wchar_t UNINSTALLATION_UNKNOWN_ERROR[] = L"Error: please uninstall the previous version of PowerToys manually."; - - const wchar_t GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT[] = L"An update to PowerToys is available. Visit our GitHub page to update.\n"; - const wchar_t GITHUB_NEW_VERSION_UNAVAILABLE[] = L"PowerToys is up to date.\n"; - const wchar_t GITHUB_NEW_VERSION_VISIT[] = L"Visit"; - const wchar_t GITHUB_NEW_VERSION_MORE_INFO[] = L"More info..."; - const wchar_t GITHUB_NEW_VERSION_ABORT[] = L"Abort"; - const wchar_t GITHUB_NEW_VERSION_SNOOZE_TITLE[] = L"Click Snooze to be reminded in:"; - const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D[] = L"1 day"; - const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D[] = L"5 days"; - const wchar_t DOWNLOAD_IN_PROGRESS[] = L"Downloading..."; - const wchar_t DOWNLOAD_COMPLETE[] = L"Download complete"; -} - namespace updating { namespace notifications { - using namespace localized_strings; using namespace ::notifications; std::wstring current_version_to_next_version(const updating::new_version_download_info& info) { @@ -51,108 +22,123 @@ namespace updating return current_version_to_next_version; } - void show_unavailable() + void show_unavailable(const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_UNAVAILABLE; - show_toast(std::move(contents), TOAST_TITLE, std::move(toast_params)); + std::wstring contents = strings.GITHUB_NEW_VERSION_UNAVAILABLE; + show_toast(std::move(contents), strings.TOAST_TITLE, std::move(toast_params)); } - void show_available(const updating::new_version_download_info& info) + void show_available(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE; + std::wstring contents = strings.GITHUB_NEW_VERSION_AVAILABLE; + contents += L'\n'; contents += current_version_to_next_version(info); show_toast_with_activations(std::move(contents), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://download_and_install_update/" }, link_button{ GITHUB_NEW_VERSION_MORE_INFO, info.release_page_uri.ToString().c_str() } }, + { link_button{ strings.GITHUB_NEW_VERSION_UPDATE_NOW, + L"powertoys://download_and_install_update/" }, + link_button{ strings.GITHUB_NEW_VERSION_MORE_INFO, + info.release_page_uri.ToString().c_str() } }, std::move(toast_params)); } - void show_download_start(const updating::new_version_download_info& info) + void show_download_start(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); progress_bar_params progress_bar_params; std::wstring progress_title{ info.version_string }; progress_title += L' '; - progress_title += localized_strings::DOWNLOAD_IN_PROGRESS; + progress_title += strings.DOWNLOAD_IN_PROGRESS; progress_bar_params.progress_title = progress_title; progress_bar_params.progress = .0f; toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false, std::move(progress_bar_params) }; - show_toast_with_activations(localized_strings::GITHUB_NEW_VERSION_DOWNLOAD_STARTED, - TOAST_TITLE, + show_toast_with_activations(strings.GITHUB_NEW_VERSION_DOWNLOAD_STARTED, + strings.TOAST_TITLE, {}, {}, std::move(toast_params)); } - void show_visit_github(const updating::new_version_download_info& info) + void show_visit_github(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT; + std::wstring contents = strings.GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT; + contents += L'\n'; contents += current_version_to_next_version(info); show_toast_with_activations(std::move(contents), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } }, + { link_button{ strings.GITHUB_NEW_VERSION_VISIT, + info.release_page_uri.ToString().c_str() } }, std::move(toast_params)); } - void show_install_error(const updating::new_version_download_info& info) + void show_install_error(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR; + std::wstring contents = strings.GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR; + contents += L'\n'; contents += current_version_to_next_version(info); show_toast_with_activations(std::move(contents), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } }, + { link_button{ strings.GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } }, std::move(toast_params)); } - void show_version_ready(const updating::new_version_download_info& info) + void show_version_ready(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring new_version_ready{ GITHUB_NEW_VERSION_READY_TO_INSTALL }; + std::wstring new_version_ready{ strings.GITHUB_NEW_VERSION_READY_TO_INSTALL }; + new_version_ready += L'\n'; new_version_ready += current_version_to_next_version(info); show_toast_with_activations(std::move(new_version_ready), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://update_now/" + info.installer_filename }, - link_button{ GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, L"powertoys://schedule_update/" + info.installer_filename }, - snooze_button{ GITHUB_NEW_VERSION_SNOOZE_TITLE, { { GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 }, { GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } } } }, + { link_button{ strings.GITHUB_NEW_VERSION_UPDATE_NOW, + L"powertoys://update_now/" + info.installer_filename }, + link_button{ strings.GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, + L"powertoys://schedule_update/" + info.installer_filename }, + snooze_button{ + strings.GITHUB_NEW_VERSION_SNOOZE_TITLE, + { { strings.GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 }, + { strings.GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } }, + strings.SNOOZE_BUTTON + } }, std::move(toast_params)); } - void show_uninstallation_error() + void show_uninstallation_error(const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); - show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR, TOAST_TITLE); + show_toast(strings.UNINSTALLATION_UNKNOWN_ERROR, strings.TOAST_TITLE); } - void update_download_progress(const updating::new_version_download_info& info, float progress) + void update_download_progress(const updating::new_version_download_info& info, float progress, const notifications::strings& strings) { progress_bar_params progress_bar_params; std::wstring progress_title{ info.version_string }; progress_title += L' '; - progress_title += progress < 1 ? localized_strings::DOWNLOAD_IN_PROGRESS : localized_strings::DOWNLOAD_COMPLETE; + progress_title += progress < 1 ? strings.DOWNLOAD_IN_PROGRESS : strings.DOWNLOAD_COMPLETE; progress_bar_params.progress_title = progress_title; progress_bar_params.progress = progress; update_toast_progress_bar(UPDATING_PROCESS_TOAST_TAG, progress_bar_params); diff --git a/src/common/updating/notifications.h b/src/common/updating/notifications.h index 30f33f0470..0bd791620f 100644 --- a/src/common/updating/notifications.h +++ b/src/common/updating/notifications.h @@ -6,14 +6,66 @@ namespace updating namespace notifications { - void show_unavailable(); - void show_available(const updating::new_version_download_info& info); - void show_download_start(const updating::new_version_download_info& info); - void show_visit_github(const updating::new_version_download_info& info); - void show_install_error(const updating::new_version_download_info& info); - void show_version_ready(const updating::new_version_download_info& info); - void show_uninstallation_error(); + struct strings + { + std::wstring GITHUB_NEW_VERSION_AVAILABLE; + std::wstring GITHUB_NEW_VERSION_DOWNLOAD_STARTED; + std::wstring GITHUB_NEW_VERSION_READY_TO_INSTALL; + std::wstring GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR; + std::wstring GITHUB_NEW_VERSION_UPDATE_NOW; + std::wstring GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART; + std::wstring UNINSTALLATION_UNKNOWN_ERROR; + std::wstring GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT; + std::wstring GITHUB_NEW_VERSION_UNAVAILABLE; + std::wstring GITHUB_NEW_VERSION_VISIT; + std::wstring GITHUB_NEW_VERSION_MORE_INFO; + std::wstring GITHUB_NEW_VERSION_ABORT; + std::wstring GITHUB_NEW_VERSION_SNOOZE_TITLE; + std::wstring SNOOZE_BUTTON; + std::wstring GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D; + std::wstring GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D; + std::wstring DOWNLOAD_IN_PROGRESS; + std::wstring DOWNLOAD_COMPLETE; + std::wstring TOAST_TITLE; + std::wstring OFFER_UNINSTALL_MSI; + std::wstring OFFER_UNINSTALL_MSI_TITLE; + template + static strings create() + { + return strings{ + .GITHUB_NEW_VERSION_AVAILABLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE), + .GITHUB_NEW_VERSION_DOWNLOAD_STARTED = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_DOWNLOAD_STARTED), + .GITHUB_NEW_VERSION_READY_TO_INSTALL = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_READY_TO_INSTALL), + .GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR), + .GITHUB_NEW_VERSION_UPDATE_NOW = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_NOW), + .GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART), + .UNINSTALLATION_UNKNOWN_ERROR = GET_RESOURCE_STRING(IDS_UNINSTALLATION_UNKNOWN_ERROR), + .GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT), + .GITHUB_NEW_VERSION_UNAVAILABLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UNAVAILABLE), + .GITHUB_NEW_VERSION_VISIT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_VISIT), + .GITHUB_NEW_VERSION_MORE_INFO = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), + .GITHUB_NEW_VERSION_ABORT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_ABORT), + .GITHUB_NEW_VERSION_SNOOZE_TITLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_SNOOZE_TITLE), + .SNOOZE_BUTTON = GET_RESOURCE_STRING(IDS_SNOOZE_BUTTON), + .GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D), + .GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D), + .DOWNLOAD_IN_PROGRESS = GET_RESOURCE_STRING(IDS_DOWNLOAD_IN_PROGRESS), + .DOWNLOAD_COMPLETE = GET_RESOURCE_STRING(IDS_DOWNLOAD_COMPLETE), + .TOAST_TITLE = GET_RESOURCE_STRING(IDS_TOAST_TITLE), + .OFFER_UNINSTALL_MSI = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI), + .OFFER_UNINSTALL_MSI_TITLE = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI_TITLE) + }; + } + }; - void update_download_progress(const updating::new_version_download_info& info, float progress); + void show_unavailable(const notifications::strings& strings); + void show_available(const updating::new_version_download_info& info, const strings&); + void show_download_start(const updating::new_version_download_info& info, const strings&); + void show_visit_github(const updating::new_version_download_info& info, const strings&); + void show_install_error(const updating::new_version_download_info& info, const strings&); + void show_version_ready(const updating::new_version_download_info& info, const strings&); + void show_uninstallation_error(const notifications::strings& strings); + + void update_download_progress(const updating::new_version_download_info& info, float progress, const notifications::strings& strings); } } \ No newline at end of file diff --git a/src/common/updating/updating.cpp b/src/common/updating/updating.cpp index c2f0e6e536..0160d4b0fc 100644 --- a/src/common/updating/updating.cpp +++ b/src/common/updating/updating.cpp @@ -19,7 +19,7 @@ #include "VersionHelper.h" #include -namespace +namespace // Strings in this namespace should not be localized { const wchar_t POWER_TOYS_UPGRADE_CODE[] = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}"; const wchar_t POWERTOYS_EXE_COMPONENT[] = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}"; @@ -32,12 +32,6 @@ namespace const wchar_t TOAST_TITLE[] = L"PowerToys"; } -namespace localized_strings -{ - const wchar_t OFFER_UNINSTALL_MSI[] = L"We've detected a previous installation of PowerToys. Would you like to remove it?"; - const wchar_t OFFER_UNINSTALL_MSI_TITLE[] = L"PowerToys: uninstall previous version?"; -} - namespace updating { std::wstring get_msi_package_path() @@ -73,13 +67,18 @@ namespace updating return package_path; } - bool offer_msi_uninstallation() + bool offer_msi_uninstallation(const notifications::strings& strings) { - const auto selection = SHMessageBoxCheckW(nullptr, localized_strings::OFFER_UNINSTALL_MSI, localized_strings::OFFER_UNINSTALL_MSI_TITLE, MB_ICONQUESTION | MB_YESNO, IDNO, DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH); + const auto selection = SHMessageBoxCheckW(nullptr, + strings.OFFER_UNINSTALL_MSI.c_str(), + strings.OFFER_UNINSTALL_MSI_TITLE.c_str(), + MB_ICONQUESTION | MB_YESNO, + IDNO, + DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH); return selection == IDYES; } - bool uninstall_msi_version(const std::wstring& package_path) + bool uninstall_msi_version(const std::wstring& package_path, const notifications::strings& strings) { const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL"); if (ERROR_SUCCESS == uninstall_result) @@ -94,7 +93,7 @@ namespace updating } catch (...) { - updating::notifications::show_uninstallation_error(); + updating::notifications::show_uninstallation_error(strings); } } return false; @@ -202,7 +201,7 @@ namespace updating return installer_download_dst; } - std::future try_autoupdate(const bool download_updates_automatically) + std::future try_autoupdate(const bool download_updates_automatically, const notifications::strings& strings) { const auto new_version = co_await get_new_github_version_info_async(); if (!new_version) @@ -230,32 +229,32 @@ namespace updating } if (!download_success) { - updating::notifications::show_install_error(new_version.value()); + updating::notifications::show_install_error(new_version.value(), strings); co_return; } - updating::notifications::show_version_ready(new_version.value()); + updating::notifications::show_version_ready(new_version.value(), strings); } else { - updating::notifications::show_visit_github(new_version.value()); + updating::notifications::show_visit_github(new_version.value(), strings); } } - std::future check_new_version_available() + std::future check_new_version_available(const notifications::strings& strings) { const auto new_version = co_await get_new_github_version_info_async(); if (!new_version) { - updating::notifications::show_unavailable(); + updating::notifications::show_unavailable(strings); co_return VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring(); } - updating::notifications::show_available(new_version.value()); + updating::notifications::show_available(new_version.value(), strings); co_return new_version->version_string; } - std::future download_update() + std::future download_update(const notifications::strings& strings) { const auto new_version = co_await get_new_github_version_info_async(); if (!new_version) @@ -264,12 +263,12 @@ namespace updating } auto installer_download_dst = create_download_path() / new_version->installer_filename; - updating::notifications::show_download_start(new_version.value()); + updating::notifications::show_download_start(new_version.value(), strings); try { auto progressUpdateHandle = [&](float progress) { - updating::notifications::update_download_progress(new_version.value(), progress); + updating::notifications::update_download_progress(new_version.value(), progress, strings); }; http::HttpClient client; @@ -277,7 +276,7 @@ namespace updating } catch (...) { - updating::notifications::show_install_error(new_version.value()); + updating::notifications::show_install_error(new_version.value(), strings); co_return L""; } diff --git a/src/common/updating/updating.h b/src/common/updating/updating.h index 597a866b16..ea993f6d60 100644 --- a/src/common/updating/updating.h +++ b/src/common/updating/updating.h @@ -6,13 +6,14 @@ #include #include +#include "notifications.h" #include "../VersionHelper.h" namespace updating { std::wstring get_msi_package_path(); - bool uninstall_msi_version(const std::wstring& package_path); - bool offer_msi_uninstallation(); + bool uninstall_msi_version(const std::wstring& package_path, const notifications::strings&); + bool offer_msi_uninstallation(const notifications::strings&); std::optional get_msi_package_installed_path(); std::optional get_installed_powertoys_version(); @@ -27,11 +28,11 @@ namespace updating }; std::future> get_new_github_version_info_async(); - std::future try_autoupdate(const bool download_updates_automatically); + std::future try_autoupdate(const bool download_updates_automatically, const notifications::strings&); std::filesystem::path get_pending_updates_path(); - std::future check_new_version_available(); - std::future download_update(); + std::future check_new_version_available(const notifications::strings&); + std::future download_update(const notifications::strings&); // non-localized constexpr inline std::wstring_view INSTALLER_FILENAME_PATTERN = L"powertoyssetup"; diff --git a/src/runner/LocProject.json b/src/runner/LocProject.json index 640d8f23ce..a7978f0a33 100644 --- a/src/runner/LocProject.json +++ b/src/runner/LocProject.json @@ -4,9 +4,9 @@ "LanguageSet": "Azure_Languages", "LocItems": [ { - "SourceFile": "src\\action_runner\\Resources.resx", + "SourceFile": "src\\runner\\Resources.resx", "CopyOption": "LangIDOnName", - "OutputPath": "src\\action_runner" + "OutputPath": "src\\runner" } ] } diff --git a/src/runner/Resources.resx b/src/runner/Resources.resx index 50f74f777e..836c1340d3 100644 --- a/src/runner/Resources.resx +++ b/src/runner/Resources.resx @@ -73,5 +73,85 @@ PowerToys was successfully updated! - + + An older version of PowerToys is already running. + + + Couldn't download PowerToys update! Please report the issue on Github. + + + An older MSIX version of PowerToys was uninstalled. + + + PowerToys was updated successfully! + + + This setting has been disabled by your administrator. + + + This setting has been disabled manually via <a href="https://ms_settings_startupapps" target="_blank">Startup Settings</a>. + + + An update to PowerToys is available. + + + PowerToys download started. + + + An update to PowerToys is ready to install. + + + Error: couldn't download PowerToys installer. Visit our GitHub page to update. + + + Update now + + + At next launch + + + Error: please uninstall the previous version of PowerToys manually. + + + An update to PowerToys is available. Visit our GitHub page to update. + + + PowerToys is up to date. + + + Visit + + + More info... + + + Abort + + + Click Snooze to be reminded in: + + + 1 day + + + 5 days + + + Downloading... + + + Download complete + + + PowerToys Update + + + We've detected a previous installation of PowerToys. Would you like to remove it? + + + PowerToys: uninstall previous version? + + + Snooze + \ No newline at end of file diff --git a/src/runner/general_settings.cpp b/src/runner/general_settings.cpp index a1f4ce357a..5c7e950da5 100644 --- a/src/runner/general_settings.cpp +++ b/src/runner/general_settings.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "general_settings.h" #include "auto_start_helper.h" +#include "Generated files/resource.h" #include #include @@ -15,12 +16,7 @@ static std::wstring settings_theme = L"system"; static bool run_as_elevated = false; static bool download_updates_automatically = true; -// TODO: add resource.rc for settings project and localize -namespace localized_strings -{ - const std::wstring_view STARTUP_DISABLED_BY_POLICY = L"This setting has been disabled by your administrator."; - const std::wstring_view STARTUP_DISABLED_BY_USER = LR"(This setting has been disabled manually via Startup Settings.)"; -} +extern "C" IMAGE_DOS_HEADER __ImageBase; json::JsonObject GeneralSettings::to_json() { @@ -81,7 +77,6 @@ GeneralSettings get_general_settings() if (winstore::running_as_packaged()) { - using namespace localized_strings; const auto task_state = winstore::get_startup_task_status_async().get(); switch (task_state) { @@ -92,11 +87,11 @@ GeneralSettings get_general_settings() settings.isStartupEnabled = true; break; case winstore::StartupTaskState::DisabledByPolicy: - settings.startupDisabledReason = STARTUP_DISABLED_BY_POLICY; + settings.startupDisabledReason = GET_RESOURCE_STRING(IDS_STARTUP_DISABLED_BY_POLICY); settings.isStartupEnabled = false; break; case winstore::StartupTaskState::DisabledByUser: - settings.startupDisabledReason = STARTUP_DISABLED_BY_USER; + settings.startupDisabledReason = GET_RESOURCE_STRING(IDS_STARTUP_DISABLED_BY_USER); settings.isStartupEnabled = false; break; } diff --git a/src/runner/main.cpp b/src/runner/main.cpp index ec7a56ad0c..d68a1fec1d 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -35,20 +35,12 @@ #endif extern "C" IMAGE_DOS_HEADER __ImageBase; - -namespace localized_strings -{ - const wchar_t MSI_VERSION_IS_ALREADY_RUNNING[] = L"An older version of PowerToys is already running."; - const wchar_t DOWNLOAD_UPDATE_ERROR[] = L"Couldn't download PowerToys update! Please report the issue on Github."; - const wchar_t OLDER_MSIX_UNINSTALLED[] = L"An older MSIX version of PowerToys was uninstalled."; - const wchar_t PT_UPDATE_MESSAGE_BOX_TEXT[] = L"PowerToys was updated successfully!"; - const wchar_t POWER_TOYS[] = L"PowerToys"; - const wchar_t POWER_TOYS_MODULE_LOAD_FAIL[] = L"Failed to load "; // Module name will be appended on this message and it is not localized. -} +extern updating::notifications::strings Strings; namespace { const wchar_t PT_URI_PROTOCOL_SCHEME[] = L"powertoys://"; + const wchar_t POWER_TOYS_MODULE_LOAD_FAIL[] = L"Failed to load "; // Module name will be appended on this message and it is not localized. } void chdir_current_executable() @@ -59,7 +51,7 @@ void chdir_current_executable() PathRemoveFileSpec(executable_path); if (!SetCurrentDirectory(executable_path)) { - show_last_error_message(L"Change Directory to Executable Path", GetLastError()); + show_last_error_message(L"Change Directory to Executable Path", GetLastError(), L"PowerToys - runner"); } } @@ -110,7 +102,7 @@ int runner(bool isProcessElevated) std::thread{ [] { if (updating::uninstall_previous_msix_version_async().get()) { - notifications::show_toast(localized_strings::OLDER_MSIX_UNINSTALLED, L"PowerToys"); + notifications::show_toast(GET_RESOURCE_STRING(IDS_OLDER_MSIX_UNINSTALLED).c_str(), L"PowerToys"); } } }.detach(); } @@ -140,11 +132,12 @@ int runner(bool isProcessElevated) } catch (...) { - std::wstring errorMessage = std::wstring(localized_strings::POWER_TOYS_MODULE_LOAD_FAIL) + moduleSubdir.data(); - MessageBox(NULL, - errorMessage.c_str(), - localized_strings::POWER_TOYS, - MB_OK | MB_ICONERROR); + std::wstring errorMessage = POWER_TOYS_MODULE_LOAD_FAIL; + errorMessage += moduleSubdir; + MessageBoxW(NULL, + errorMessage.c_str(), + L"PowerToys", + MB_OK | MB_ICONERROR); } } // Start initial powertoys @@ -243,7 +236,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_ { try { - std::wstring installer_filename = updating::download_update().get(); + std::wstring installer_filename = updating::download_update(Strings).get(); std::wstring args{ UPDATE_NOW_LAUNCH_STAGE1_CMDARG }; args += L' '; @@ -255,7 +248,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_ catch (...) { MessageBoxW(nullptr, - localized_strings::DOWNLOAD_UPDATE_ERROR, + GET_RESOURCE_STRING(IDS_DOWNLOAD_UPDATE_ERROR).c_str(), L"PowerToys", MB_ICONWARNING | MB_OK); @@ -314,7 +307,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine case SpecialMode::ReportSuccessfulUpdate: { notifications::remove_toasts(notifications::UPDATING_PROCESS_TOAST_TAG); - notifications::show_toast(localized_strings::PT_UPDATE_MESSAGE_BOX_TEXT, + notifications::show_toast(GET_RESOURCE_STRING(IDS_PT_UPDATE_MESSAGE_BOX_TEXT), L"PowerToys", notifications::toast_params{ notifications::UPDATING_PROCESS_TOAST_TAG }); break; diff --git a/src/runner/settings_window.cpp b/src/runner/settings_window.cpp index a6d0786672..83b3dd7647 100644 --- a/src/runner/settings_window.cpp +++ b/src/runner/settings_window.cpp @@ -390,7 +390,7 @@ void run_settings_window() WaitForSingleObject(process_info.hProcess, INFINITE); if (WaitForSingleObject(process_info.hProcess, INFINITE) != WAIT_OBJECT_0) { - show_last_error_message(L"Couldn't wait on the Settings Window to close.", GetLastError()); + show_last_error_message(L"Couldn't wait on the Settings Window to close.", GetLastError(), L"PowerToys - runner"); } LExit: diff --git a/src/runner/update_utils.cpp b/src/runner/update_utils.cpp index c66d16dbeb..5a2f30eb8b 100644 --- a/src/runner/update_utils.cpp +++ b/src/runner/update_utils.cpp @@ -1,5 +1,8 @@ #include "pch.h" +#include +#include "Generated Files/resource.h" + #include "action_runner_utils.h" #include "update_state.h" #include "update_utils.h" @@ -8,6 +11,10 @@ #include #include +extern "C" IMAGE_DOS_HEADER __ImageBase; + +auto Strings = updating::notifications::strings::create(); + bool start_msi_uninstallation_sequence() { const auto package_path = updating::get_msi_package_path(); @@ -18,7 +25,7 @@ bool start_msi_uninstallation_sequence() return true; } - if (!updating::offer_msi_uninstallation()) + if (!updating::offer_msi_uninstallation(Strings)) { // User declined to uninstall or opted for "Don't show again" return false; @@ -54,7 +61,7 @@ void github_update_worker() const bool download_updates_automatically = get_general_settings().downloadUpdatesAutomatically; try { - updating::try_autoupdate(download_updates_automatically).get(); + updating::try_autoupdate(download_updates_automatically, Strings).get(); } catch (...) { @@ -70,7 +77,7 @@ std::wstring check_for_updates() { try { - return updating::check_new_version_available().get(); + return updating::check_new_version_available(Strings).get(); } catch (...) {