Files
ClaudeDo/src/ClaudeDo.Installer/Views/WizardViewModel.cs
mika kuns 364a037cb3 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 <noreply@anthropic.com>
2026-06-03 12:55:08 +02:00

105 lines
3.0 KiB
C#

using System.Linq;
using System.Windows;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Pages.InstallPage;
using ClaudeDo.Installer.Pages.WelcomePage;
using ClaudeDo.Localization;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ClaudeDo.Installer.Views;
public partial class WizardViewModel : ObservableObject
{
private readonly InstallContext _context;
private readonly ILocalizer _localizer;
public IReadOnlyList<IInstallerPage> Pages { get; }
public IReadOnlyList<LanguageOption> Languages { get; }
[ObservableProperty]
private LanguageOption? _selectedLanguage;
partial void OnSelectedLanguageChanged(LanguageOption? value)
{
if (value is null) return;
_localizer.SetLanguage(value.Value.Code);
_context.Language = value.Value.Code;
}
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanGoBack))]
[NotifyPropertyChangedFor(nameof(IsLastPage))]
[NotifyPropertyChangedFor(nameof(NextButtonText))]
[NotifyPropertyChangedFor(nameof(CurrentPage))]
private int _currentPageIndex;
public IInstallerPage CurrentPage => Pages[CurrentPageIndex];
public bool CanGoBack => CurrentPageIndex > 0;
public bool IsLastPage => CurrentPageIndex == Pages.Count - 1;
public string NextButtonText => IsLastPage
? (_localizer["installer.nav.install"])
: (_localizer["installer.nav.next"]);
[ObservableProperty]
private string? _validationError;
public WizardViewModel(PageResolver resolver, InstallContext context, ILocalizer localizer)
{
_context = context;
_localizer = localizer;
Languages = localizer.AvailableLanguages;
_selectedLanguage = Languages.FirstOrDefault(l => l.Code == localizer.CurrentCode);
_context.Language = localizer.CurrentCode;
var all = resolver.WizardPages;
Pages = context.Mode == InstallerMode.Update
? all.Where(p => p is WelcomePageViewModel
|| p is InstallPageViewModel).ToList()
: all;
if (Pages.Count > 0)
_ = InitAsync();
}
private async Task InitAsync()
{
try { await Pages[0].LoadAsync(); }
catch { /* first page loads with defaults on error */ }
}
[RelayCommand]
private async Task GoBack()
{
if (!CanGoBack) return;
CurrentPageIndex--;
await CurrentPage.LoadAsync();
ValidationError = null;
}
[RelayCommand]
private async Task GoNext()
{
if (!CurrentPage.Validate())
{
ValidationError = "Please fix the highlighted errors before continuing.";
return;
}
ValidationError = null;
await CurrentPage.ApplyAsync();
if (CurrentPageIndex < Pages.Count - 1)
{
CurrentPageIndex++;
await CurrentPage.LoadAsync();
}
}
[RelayCommand]
private void Close()
{
Application.Current.Shutdown();
}
}