From 0d4f126e3af1cc8e1f38535f9eeeef47e8c9f350 Mon Sep 17 00:00:00 2001 From: "j.foucher" Date: Sat, 2 May 2026 13:56:52 +0200 Subject: [PATCH] i18n: localize all MessageBox dialogs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous batch only covered XAML strings. The runtime MessageBox dialogs (errors, confirmations, info popups) stayed hardcoded in French, breaking immersion for non-FR users. Added ~15 keys to Strings.cs for the MessageBox bodies and titles: - error / launch error / confirm / info / patience / language change / release notes (titles) - launch failed / self-update failed / install failed / uninstall failed / uninstall confirm with version+folder+size / no release notes / fetch failed / clear cache confirm / deactivate license (short and detailed) / language restart (bodies) Some are parametrized (MsgLaunchFailed(detail), MsgUninstallConfirm (version, folder, size)) so the localized strings interpolate the runtime values cleanly across all 5 languages. Replaced every MessageBox.Show in MainViewModel, SettingsViewModel and LicenseDetailsDialog.xaml.cs to use these keys. The "Échec : " prefix in the cache-clear error was dropped — the error message alone is sufficient with Strings.MsgBoxError as the dialog title. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ViewModels/MainViewModel.cs | 31 ++--- .../ViewModels/SettingsViewModel.cs | 15 +-- .../Views/LicenseDetailsDialog.xaml.cs | 7 +- src/PSLauncher.Core/Localization/Strings.cs | 106 ++++++++++++++++++ 4 files changed, 133 insertions(+), 26 deletions(-) diff --git a/src/PSLauncher.App/ViewModels/MainViewModel.cs b/src/PSLauncher.App/ViewModels/MainViewModel.cs index 51b1541..1968ce1 100644 --- a/src/PSLauncher.App/ViewModels/MainViewModel.cs +++ b/src/PSLauncher.App/ViewModels/MainViewModel.cs @@ -12,6 +12,7 @@ using PSLauncher.Core.Configuration; using PSLauncher.Core.Downloads; using PSLauncher.Core.Installations; using PSLauncher.Core.Licensing; +using PSLauncher.Core.Localization; using PSLauncher.Core.Manifests; using PSLauncher.Core.Process; using PSLauncher.Core.Updates; @@ -338,8 +339,8 @@ public sealed partial class MainViewModel : ObservableObject catch (Exception ex) { _logger.LogError(ex, "Self-update failed"); - MessageBox.Show($"Mise à jour du launcher échouée :\n\n{ex.Message}", - "Erreur", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show(Strings.MsgSelfUpdateFailed(ex.Message), + Strings.MsgBoxError, MessageBoxButton.OK, MessageBoxImage.Error); StatusMessage = $"Erreur self-update : {ex.Message}"; IsBusy = false; } @@ -463,15 +464,15 @@ public sealed partial class MainViewModel : ObservableObject catch (Exception ex) { _logger.LogError(ex, "Launch failed"); - MessageBox.Show($"Impossible de lancer la version :\n\n{ex.Message}", - "Erreur de lancement", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show(Strings.MsgLaunchFailed(ex.Message), + Strings.MsgBoxLaunchError, MessageBoxButton.OK, MessageBoxImage.Error); } } private async Task InstallVersionAsync(VersionRowViewModel row) { if (row.Remote is null) return; - if (IsBusy) { MessageBox.Show("Une autre opération est déjà en cours.", "Patience", MessageBoxButton.OK, MessageBoxImage.Information); return; } + if (IsBusy) { MessageBox.Show(Strings.MsgBusy, Strings.MsgBoxPatience, MessageBoxButton.OK, MessageBoxImage.Information); return; } IsBusy = true; _activeRow = row; @@ -555,8 +556,8 @@ public sealed partial class MainViewModel : ObservableObject row.ProgressDetail = null; row.ProgressPercent = 0; MessageBox.Show( - $"Le téléchargement ou l'installation a échoué :\n\n{ex.Message}", - "Erreur", MessageBoxButton.OK, MessageBoxImage.Error); + Strings.MsgInstallFailed(ex.Message), + Strings.MsgBoxError, MessageBoxButton.OK, MessageBoxImage.Error); StatusMessage = $"Erreur : {ex.Message}"; _toastService.ShowError($"Échec v{row.Version}", ex.Message); } @@ -575,13 +576,13 @@ public sealed partial class MainViewModel : ObservableObject var sizeStr = FormatSize(row.SizeBytes); var confirm = MessageBox.Show( - $"Supprimer la version v{row.Version} ?\n\nDossier : {row.FolderPath}\nLibérera {sizeStr}.\n\nCette action est irréversible.", - "Confirmer la suppression", + Strings.MsgUninstallConfirm(row.Version, row.FolderPath, sizeStr), + Strings.MsgBoxConfirm, MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (confirm != MessageBoxResult.Yes) return; - if (IsBusy) { MessageBox.Show("Une autre opération est déjà en cours.", "Patience", MessageBoxButton.OK, MessageBoxImage.Information); return; } + if (IsBusy) { MessageBox.Show(Strings.MsgBusy, Strings.MsgBoxPatience, MessageBoxButton.OK, MessageBoxImage.Information); return; } IsBusy = true; row.State = VersionRowState.Uninstalling; @@ -596,7 +597,7 @@ public sealed partial class MainViewModel : ObservableObject { _logger.LogError(ex, "Uninstall failed for {Version}", row.Version); row.State = VersionRowState.InstalledIdle; - MessageBox.Show($"Suppression échouée : {ex.Message}", "Erreur", + MessageBox.Show(Strings.MsgUninstallFailed(ex.Message), Strings.MsgBoxError, MessageBoxButton.OK, MessageBoxImage.Error); StatusMessage = $"Erreur : {ex.Message}"; } @@ -611,8 +612,8 @@ public sealed partial class MainViewModel : ObservableObject var url = row.Remote?.ReleaseNotesUrl; if (string.IsNullOrEmpty(url)) { - MessageBox.Show("Aucune release note disponible pour cette version.", - "Release notes", MessageBoxButton.OK, MessageBoxImage.Information); + MessageBox.Show(Strings.MsgNoReleaseNotes, + Strings.MsgBoxReleaseNotes, MessageBoxButton.OK, MessageBoxImage.Information); return; } string notes; @@ -620,8 +621,8 @@ public sealed partial class MainViewModel : ObservableObject catch (Exception ex) { _logger.LogWarning(ex, "Failed to fetch release notes"); - MessageBox.Show($"Impossible de récupérer les release notes :\n{ex.Message}", - "Erreur", MessageBoxButton.OK, MessageBoxImage.Warning); + MessageBox.Show(Strings.MsgReleaseNotesFetchFailed(ex.Message), + Strings.MsgBoxError, MessageBoxButton.OK, MessageBoxImage.Warning); return; } diff --git a/src/PSLauncher.App/ViewModels/SettingsViewModel.cs b/src/PSLauncher.App/ViewModels/SettingsViewModel.cs index ec6be44..d64d104 100644 --- a/src/PSLauncher.App/ViewModels/SettingsViewModel.cs +++ b/src/PSLauncher.App/ViewModels/SettingsViewModel.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using PSLauncher.Core.Configuration; using PSLauncher.Core.Downloads; using PSLauncher.Core.Licensing; +using PSLauncher.Core.Localization; using PSLauncher.Models; namespace PSLauncher.App.ViewModels; @@ -185,8 +186,8 @@ public sealed partial class SettingsViewModel : ObservableObject private void ClearCache() { var confirm = MessageBox.Show( - "Vider le cache de téléchargements ? Les téléchargements en cours/pause seront perdus.", - "Confirmer", + Strings.MsgClearCacheConfirm, + Strings.MsgBoxConfirm, MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (confirm != MessageBoxResult.Yes) return; @@ -201,7 +202,7 @@ public sealed partial class SettingsViewModel : ObservableObject catch (Exception ex) { _logger.LogError(ex, "ClearCache failed"); - MessageBox.Show("Échec : " + ex.Message, "Erreur", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show(ex.Message, Strings.MsgBoxError, MessageBoxButton.OK, MessageBoxImage.Error); } } @@ -232,8 +233,8 @@ public sealed partial class SettingsViewModel : ObservableObject // la nouvelle langue. Plutôt que de demander à l'utilisateur de fermer/rouvrir, // on spawne un cmd qui attend la fermeture puis relance. var ok = MessageBox.Show( - "Le launcher va redémarrer pour appliquer la nouvelle langue.", - "Changement de langue", + Strings.MsgLanguageRestart, + Strings.MsgBoxLanguageChange, MessageBoxButton.OKCancel, MessageBoxImage.Information, MessageBoxResult.OK); if (ok == MessageBoxResult.OK) { @@ -263,8 +264,8 @@ public sealed partial class SettingsViewModel : ObservableObject private void DeactivateLicense() { var confirm = MessageBox.Show( - "Désactiver la license sur cette machine ?\nTu pourras la réactiver avec ta clé.", - "Confirmer", + Strings.MsgDeactivateLicenseConfirm, + Strings.MsgBoxConfirm, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); if (confirm != MessageBoxResult.Yes) return; _licenseService.Clear(); diff --git a/src/PSLauncher.App/Views/LicenseDetailsDialog.xaml.cs b/src/PSLauncher.App/Views/LicenseDetailsDialog.xaml.cs index d8f2560..3022d7c 100644 --- a/src/PSLauncher.App/Views/LicenseDetailsDialog.xaml.cs +++ b/src/PSLauncher.App/Views/LicenseDetailsDialog.xaml.cs @@ -1,6 +1,7 @@ using System.Windows; using System.Windows.Media; using PSLauncher.Core.Licensing; +using PSLauncher.Core.Localization; using PSLauncher.Models; namespace PSLauncher.App.Views; @@ -66,10 +67,8 @@ public partial class LicenseDetailsDialog : Window private void OnDeactivate(object sender, RoutedEventArgs e) { var confirm = MessageBox.Show( - "Désactiver la license sur cette machine ?\n\n" + - "Tu pourras la réactiver plus tard avec ta clé. " + - "Les versions déjà installées restent utilisables.", - "Confirmer la désactivation", + Strings.MsgDeactivateLicenseDetailedConfirm, + Strings.MsgBoxConfirm, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); if (confirm != MessageBoxResult.Yes) return; _licenseService.Clear(); diff --git a/src/PSLauncher.Core/Localization/Strings.cs b/src/PSLauncher.Core/Localization/Strings.cs index c9ff8b5..b2df0df 100644 --- a/src/PSLauncher.Core/Localization/Strings.cs +++ b/src/PSLauncher.Core/Localization/Strings.cs @@ -152,4 +152,110 @@ public static class Strings // ==================== UPDATE ==================== public static string UpdateAvailableTitle => T("Mise à jour disponible", "Update available", "有可用更新", "มีการอัปเดต", "تحديث متاح"); public static string UpdateDownload => T("⬇ Télécharger", "⬇ Download", "⬇ 下载", "⬇ ดาวน์โหลด", "⬇ تنزيل"); + + // ==================== MESSAGEBOX TITLES ==================== + public static string MsgBoxError => T("Erreur", "Error", "错误", "ข้อผิดพลาด", "خطأ"); + public static string MsgBoxLaunchError => T("Erreur de lancement", "Launch error", "启动错误", "เปิดใช้งานล้มเหลว", "خطأ في التشغيل"); + public static string MsgBoxConfirm => T("Confirmer", "Confirm", "确认", "ยืนยัน", "تأكيد"); + public static string MsgBoxInfo => T("Information", "Information", "信息", "ข้อมูล", "معلومة"); + public static string MsgBoxPatience => T("Patience", "Please wait", "请稍候", "โปรดรอ", "يرجى الانتظار"); + public static string MsgBoxLanguageChange => T("Changement de langue", "Language change", "更改语言", "เปลี่ยนภาษา", "تغيير اللغة"); + public static string MsgBoxReleaseNotes => T("Release notes", "Release notes", "版本说明", "บันทึกการเปลี่ยนแปลง", "ملاحظات الإصدار"); + + // ==================== MESSAGEBOX MESSAGES ==================== + public static string MsgBusy => T( + "Une autre opération est déjà en cours.", + "Another operation is already in progress.", + "另一个操作正在进行中。", + "มีการดำเนินการอื่นอยู่แล้ว", + "هناك عملية أخرى قيد التنفيذ بالفعل." + ); + + public static string MsgLaunchFailed(string detail) => T( + $"Impossible de lancer la version :\n\n{detail}", + $"Could not launch the version:\n\n{detail}", + $"无法启动该版本:\n\n{detail}", + $"ไม่สามารถเปิดเวอร์ชันนี้ได้:\n\n{detail}", + $"تعذر تشغيل النسخة:\n\n{detail}" + ); + + public static string MsgSelfUpdateFailed(string detail) => T( + $"Mise à jour du launcher échouée :\n\n{detail}", + $"Launcher update failed:\n\n{detail}", + $"启动器更新失败:\n\n{detail}", + $"การอัปเดต Launcher ล้มเหลว:\n\n{detail}", + $"فشل تحديث المُشغِّل:\n\n{detail}" + ); + + public static string MsgInstallFailed(string detail) => T( + $"Le téléchargement ou l'installation a échoué :\n\n{detail}", + $"Download or installation failed:\n\n{detail}", + $"下载或安装失败:\n\n{detail}", + $"การดาวน์โหลดหรือติดตั้งล้มเหลว:\n\n{detail}", + $"فشل التنزيل أو التثبيت:\n\n{detail}" + ); + + public static string MsgUninstallFailed(string detail) => T( + $"Suppression échouée : {detail}", + $"Uninstall failed: {detail}", + $"卸载失败:{detail}", + $"การถอนการติดตั้งล้มเหลว: {detail}", + $"فشل الإزالة: {detail}" + ); + + public static string MsgUninstallConfirm(string version, string folder, string size) => T( + $"Supprimer la version v{version} ?\n\nDossier : {folder}\nLibérera {size}.\n\nCette action est irréversible.", + $"Uninstall version v{version}?\n\nFolder: {folder}\nWill free {size}.\n\nThis action is irreversible.", + $"卸载版本 v{version}?\n\n文件夹:{folder}\n将释放 {size}。\n\n此操作不可逆。", + $"ถอนการติดตั้งเวอร์ชัน v{version}?\n\nโฟลเดอร์: {folder}\nจะคืนพื้นที่ {size}\n\nการกระทำนี้ไม่สามารถย้อนกลับได้", + $"إلغاء تثبيت النسخة v{version}؟\n\nالمجلد: {folder}\nسيتم تحرير {size}.\n\nهذا الإجراء لا رجعة فيه." + ); + + public static string MsgNoReleaseNotes => T( + "Aucune release note disponible pour cette version.", + "No release notes available for this version.", + "此版本没有可用的版本说明。", + "ไม่มีบันทึกการเปลี่ยนแปลงสำหรับเวอร์ชันนี้", + "لا توجد ملاحظات إصدار متاحة لهذه النسخة." + ); + + public static string MsgReleaseNotesFetchFailed(string detail) => T( + $"Impossible de récupérer les release notes :\n{detail}", + $"Could not fetch release notes:\n{detail}", + $"无法获取版本说明:\n{detail}", + $"ไม่สามารถดึงบันทึกการเปลี่ยนแปลงได้:\n{detail}", + $"تعذر جلب ملاحظات الإصدار:\n{detail}" + ); + + public static string MsgClearCacheConfirm => T( + "Vider le cache de téléchargements ? Les téléchargements en cours/pause seront perdus.", + "Clear the download cache? In-progress / paused downloads will be lost.", + "清空下载缓存?正在进行或暂停的下载将丢失。", + "ล้างแคชดาวน์โหลด? การดาวน์โหลดที่กำลังดำเนินการ/หยุดชั่วคราวจะสูญหาย", + "مسح ذاكرة التخزين المؤقت للتنزيلات؟ ستفقد التنزيلات قيد التقدم أو الموقوفة مؤقتًا." + ); + + public static string MsgDeactivateLicenseConfirm => T( + "Désactiver la license sur cette machine ?\nTu pourras la réactiver avec ta clé.", + "Deactivate the license on this machine?\nYou can reactivate it later with your key.", + "在此机器上停用许可证?\n您可以稍后用密钥重新激活。", + "ปิดใช้งานใบอนุญาตบนเครื่องนี้?\nคุณสามารถเปิดใช้งานใหม่ในภายหลังด้วยคีย์ของคุณ", + "إلغاء تنشيط الترخيص على هذا الجهاز؟\nيمكنك إعادة تنشيطه لاحقًا بمفتاحك." + ); + + public static string MsgDeactivateLicenseDetailedConfirm => T( + "Désactiver la license sur cette machine ?\n\nTu pourras la réactiver plus tard avec ta clé. Les versions déjà installées restent utilisables.", + "Deactivate the license on this machine?\n\nYou can reactivate it later with your key. Already-installed versions remain usable.", + "在此机器上停用许可证?\n\n您可以稍后用密钥重新激活。已安装的版本仍可使用。", + "ปิดใช้งานใบอนุญาตบนเครื่องนี้?\n\nคุณสามารถเปิดใช้งานใหม่ในภายหลังด้วยคีย์ของคุณ เวอร์ชันที่ติดตั้งแล้วยังคงใช้งานได้", + "إلغاء تنشيط الترخيص على هذا الجهاز؟\n\nيمكنك إعادة تنشيطه لاحقًا بمفتاحك. تظل النسخ المثبتة قابلة للاستخدام." + ); + + public static string MsgLanguageRestart => T( + "Le launcher va redémarrer pour appliquer la nouvelle langue.", + "The launcher will restart to apply the new language.", + "启动器将重启以应用新语言。", + "Launcher จะรีสตาร์ทเพื่อใช้ภาษาใหม่", + "سيتم إعادة تشغيل المُشغِّل لتطبيق اللغة الجديدة." + ); }