From 364a037cb3d42e2f4434f9aea0a4920d84636f0a Mon Sep 17 00:00:00 2001 From: mika kuns Date: Wed, 3 Jun 2026 12:55:08 +0200 Subject: [PATCH] feat(i18n): localize installer with language picker and config write-through - Init Localizer at app startup (before self-update prompt) and assign to TrExtension.Localizer - Register ILocalizer in DI; inject into WizardViewModel and SettingsViewModel - WizardViewModel: SelectedLanguage ComboBox binding with OnSelectedLanguageChanged -> SetLanguage + InstallContext.Language - WizardWindow.xaml: DockPanel wraps step chips + language ComboBox (right-aligned) - Localize all installer XAML: WizardWindow, WelcomePage, PathsPage, ServicePage, UiSettingsPage, InstallPage, SettingsWindow, SelfUpdatePromptWindow - Localize page Title properties and WizardViewModel.NextButtonText via TrExtension.Localizer - Persist chosen Language in WriteConfigStep and SettingsViewModel.Save into ui.config.json - Append installer section to en.json (nav, welcome, paths, service, uiSettings, install, settings, selfUpdate) Co-Authored-By: Claude Sonnet 4.6 --- src/ClaudeDo.Installer/App.xaml.cs | 21 +++++- src/ClaudeDo.Installer/Core/InstallContext.cs | 3 + .../Pages/InstallPage/InstallPageView.xaml | 9 +-- .../Pages/InstallPage/InstallPageViewModel.cs | 3 +- .../Pages/PathsPage/PathsPageView.xaml | 15 ++-- .../Pages/PathsPage/PathsPageViewModel.cs | 3 +- .../Pages/ServicePage/ServicePageView.xaml | 19 ++--- .../Pages/ServicePage/ServicePageViewModel.cs | 3 +- .../UiSettingsPage/UiSettingsPageView.xaml | 13 ++-- .../UiSettingsPage/UiSettingsPageViewModel.cs | 3 +- .../Pages/WelcomePage/WelcomePageView.xaml | 9 +-- .../Pages/WelcomePage/WelcomePageViewModel.cs | 10 +-- .../Steps/WriteConfigStep.cs | 1 + .../Views/SelfUpdatePromptWindow.xaml | 9 +-- .../Views/SettingsViewModel.cs | 5 ++ .../Views/SettingsWindow.xaml | 11 +-- .../Views/WizardViewModel.cs | 23 +++++- .../Views/WizardWindow.xaml | 72 ++++++++++--------- src/ClaudeDo.Localization/locales/en.json | 61 ++++++++++++++++ 19 files changed, 210 insertions(+), 83 deletions(-) diff --git a/src/ClaudeDo.Installer/App.xaml.cs b/src/ClaudeDo.Installer/App.xaml.cs index 1df27e0..6f54349 100644 --- a/src/ClaudeDo.Installer/App.xaml.cs +++ b/src/ClaudeDo.Installer/App.xaml.cs @@ -1,7 +1,12 @@ +using System.Globalization; +using System.IO; +using System.Linq; using System.Net.Http; using System.Reflection; using System.Windows; using ClaudeDo.Installer.Core; +using ClaudeDo.Installer.Localization; +using ClaudeDo.Localization; using ClaudeDo.Releases; using ClaudeDo.Installer.Pages.InstallPage; using ClaudeDo.Installer.Pages.PathsPage; @@ -22,6 +27,17 @@ public partial class App : Application { base.OnStartup(e); + // --- Initialize localizer as early as possible so all windows can use {loc:Tr} --- + var localesDir = Path.Combine(AppContext.BaseDirectory, "locales"); + var localeStore = LocaleStore.Load(localesDir); + var existingSettings = InstallerAppSettings.Load(); + var initialLang = !string.IsNullOrWhiteSpace(existingSettings.Language) + ? existingSettings.Language + : CultureResolver.Resolve(CultureInfo.CurrentUICulture.Name, + localeStore.Available.Select(l => l.Code).ToArray(), "en"); + var localizer = new Localizer(localeStore, initialLang); + TrExtension.Localizer = localizer; + // --- Self-update pre-flight --- // Resolve current exe path. Assembly.Location may point to a .dll for apphost-based // .NET apps; swap to the .exe companion when that happens. @@ -120,7 +136,7 @@ public partial class App : Application // --- Existing wizard start-up unchanged below this line --- - _services = BuildServices(); + _services = BuildServices(localizer); var context = _services.GetRequiredService(); context.InstallerVersion = GetInstallerVersion(); @@ -183,9 +199,10 @@ public partial class App : Application return infoAttr?.InformationalVersion ?? "0.0.0"; } - private static ServiceProvider BuildServices() + private static ServiceProvider BuildServices(ILocalizer localizer) { var sc = new ServiceCollection(); + sc.AddSingleton(localizer); // Core sc.AddSingleton(); diff --git a/src/ClaudeDo.Installer/Core/InstallContext.cs b/src/ClaudeDo.Installer/Core/InstallContext.cs index 920b0ba..1640b44 100644 --- a/src/ClaudeDo.Installer/Core/InstallContext.cs +++ b/src/ClaudeDo.Installer/Core/InstallContext.cs @@ -36,4 +36,7 @@ public sealed class InstallContext // WelcomePage — register the external MCP endpoint with the Claude CLI. public bool RegisterMcpWithClaude { get; set; } = true; public int ExternalMcpPort { get; set; } = 47_822; + + // Language selection (persisted to ui.config.json) + public string Language { get; set; } = ""; } diff --git a/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageView.xaml b/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageView.xaml index 94781c8..5b5ab99 100644 --- a/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageView.xaml +++ b/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageView.xaml @@ -2,6 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ClaudeDo.Installer.Pages.InstallPage" + xmlns:loc="clr-namespace:ClaudeDo.Installer.Localization" d:DataContext="{d:DesignInstance local:InstallPageViewModel}" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" @@ -17,8 +18,8 @@ - - + @@ -89,11 +90,11 @@ -