i18n: 5 languages (FR/EN/ZH/TH/AR), auto-detect from Windows + Settings picker
Localization infrastructure
---------------------------
PSLauncher.Core/Localization/Strings.cs is a static class exposing each
UI string as a static property. T(fr,en,zh,th,ar) helper switches by the
current language code. ~50 keys cover the visible top-level strings:
top bar, body, status badges, action buttons, "..." menu items, license
badge texts, Settings section headers, Onboarding dialog, Update dialog.
Bindings via x:Static in XAML:
xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
Content="{x:Static loc:Strings.ActionLaunch}"
Auto-detection
--------------
LocalConfig gains a Language field defaulting to "auto". Strings.Init()
called at App.xaml.cs OnStartup before any UI:
- "auto" (or unknown code) → reads CultureInfo.CurrentUICulture
.TwoLetterISOLanguageName, picks the matching supported language,
falls back to English.
- explicit code → forced.
The chosen culture is then propagated to CurrentCulture / CurrentUICulture
so date/number formats follow.
Settings picker
---------------
SettingsDialog gets a top section "LANGUE" with a ComboBox bound to
SettingsViewModel.AvailableLanguages (Auto / FR / EN / ZH / TH / AR).
On Save, if the language code changed, prompt the user to confirm
restart, spawn `cmd /c timeout 1 & start PSLauncher.exe` and Shutdown
the current process — the new instance picks up the language at
bootstrap.
RTL for Arabic
--------------
Strings.IsRightToLeft is true when lang=="ar". App.xaml.cs sets
window.FlowDirection = RightToLeft on the MainWindow — WPF mirrors the
layout (icons on right, text aligned right).
Translations
------------
Done as best-effort by the assistant. The product wordmark "PROSERVE"
stays untranslated (brand). Logs and debug-level messages remain in
French in code — only user-visible UI is localized. Operator can
refine translations by editing Strings.cs and rebuilding.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ using PSLauncher.Core.Downloads;
|
|||||||
using PSLauncher.Core.Installations;
|
using PSLauncher.Core.Installations;
|
||||||
using PSLauncher.Core.Integrity;
|
using PSLauncher.Core.Integrity;
|
||||||
using PSLauncher.Core.Licensing;
|
using PSLauncher.Core.Licensing;
|
||||||
|
using PSLauncher.Core.Localization;
|
||||||
using PSLauncher.Core.Manifests;
|
using PSLauncher.Core.Manifests;
|
||||||
using PSLauncher.Core.Process;
|
using PSLauncher.Core.Process;
|
||||||
using PSLauncher.Core.Updates;
|
using PSLauncher.Core.Updates;
|
||||||
@@ -63,6 +64,20 @@ public partial class App : Application
|
|||||||
"PSLauncher", "logs");
|
"PSLauncher", "logs");
|
||||||
Directory.CreateDirectory(LogsDirectory);
|
Directory.CreateDirectory(LogsDirectory);
|
||||||
|
|
||||||
|
// Bootstrap i18n : on lit d'abord la config (sans services DI) pour fixer la
|
||||||
|
// langue avant que le moindre élément XAML soit instancié.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bootstrapStore = new ConfigStore(
|
||||||
|
Microsoft.Extensions.Logging.Abstractions.NullLogger<ConfigStore>.Instance);
|
||||||
|
var bootstrapCfg = bootstrapStore.Load();
|
||||||
|
Strings.Init(bootstrapCfg.Language);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Strings.Init("auto");
|
||||||
|
}
|
||||||
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.MinimumLevel.Debug()
|
.MinimumLevel.Debug()
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
@@ -143,6 +158,9 @@ public partial class App : Application
|
|||||||
|
|
||||||
var window = _host.Services.GetRequiredService<MainWindow>();
|
var window = _host.Services.GetRequiredService<MainWindow>();
|
||||||
window.DataContext = _host.Services.GetRequiredService<MainViewModel>();
|
window.DataContext = _host.Services.GetRequiredService<MainViewModel>();
|
||||||
|
// Mise en page droite-à-gauche pour les langues RTL (arabe).
|
||||||
|
if (Strings.IsRightToLeft)
|
||||||
|
window.FlowDirection = FlowDirection.RightToLeft;
|
||||||
MainWindow = window;
|
MainWindow = window;
|
||||||
window.Show();
|
window.Show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ using PSLauncher.Models;
|
|||||||
|
|
||||||
namespace PSLauncher.App.ViewModels;
|
namespace PSLauncher.App.ViewModels;
|
||||||
|
|
||||||
|
public sealed record LanguageOption(string Code, string Name);
|
||||||
|
|
||||||
public sealed partial class SettingsViewModel : ObservableObject
|
public sealed partial class SettingsViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
private readonly IConfigStore _configStore;
|
private readonly IConfigStore _configStore;
|
||||||
@@ -29,6 +31,12 @@ public sealed partial class SettingsViewModel : ObservableObject
|
|||||||
|
|
||||||
[ObservableProperty] private string _serverBaseUrl;
|
[ObservableProperty] private string _serverBaseUrl;
|
||||||
[ObservableProperty] private string _installRoot;
|
[ObservableProperty] private string _installRoot;
|
||||||
|
[ObservableProperty] private string _language;
|
||||||
|
|
||||||
|
public IReadOnlyList<LanguageOption> AvailableLanguages { get; } =
|
||||||
|
PSLauncher.Core.Localization.Strings.Available
|
||||||
|
.Select(t => new LanguageOption(t.Code, t.Name))
|
||||||
|
.ToList();
|
||||||
[ObservableProperty] private string? _connectionStatus;
|
[ObservableProperty] private string? _connectionStatus;
|
||||||
[ObservableProperty] private bool _isTestingConnection;
|
[ObservableProperty] private bool _isTestingConnection;
|
||||||
[ObservableProperty] private string _cacheSizeDisplay = "—";
|
[ObservableProperty] private string _cacheSizeDisplay = "—";
|
||||||
@@ -102,6 +110,7 @@ public sealed partial class SettingsViewModel : ObservableObject
|
|||||||
|
|
||||||
_serverBaseUrl = config.ServerBaseUrl;
|
_serverBaseUrl = config.ServerBaseUrl;
|
||||||
_installRoot = config.InstallRoot;
|
_installRoot = config.InstallRoot;
|
||||||
|
_language = string.IsNullOrWhiteSpace(config.Language) ? "auto" : config.Language;
|
||||||
|
|
||||||
LauncherVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0";
|
LauncherVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0";
|
||||||
MachineId = licenseService.GetMachineId();
|
MachineId = licenseService.GetMachineId();
|
||||||
@@ -201,10 +210,48 @@ public sealed partial class SettingsViewModel : ObservableObject
|
|||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void Save()
|
private void Save()
|
||||||
{
|
{
|
||||||
|
var languageChanged = !string.Equals(
|
||||||
|
(_config.Language ?? "auto").ToLowerInvariant(),
|
||||||
|
(Language ?? "auto").ToLowerInvariant(),
|
||||||
|
StringComparison.Ordinal);
|
||||||
|
|
||||||
_config.ServerBaseUrl = ServerBaseUrl.TrimEnd('/');
|
_config.ServerBaseUrl = ServerBaseUrl.TrimEnd('/');
|
||||||
_config.InstallRoot = InstallRoot;
|
_config.InstallRoot = InstallRoot;
|
||||||
|
_config.Language = Language ?? "auto";
|
||||||
_configStore.Save(_config);
|
_configStore.Save(_config);
|
||||||
_logger.LogInformation("Settings saved");
|
_logger.LogInformation("Settings saved (language={Lang}, changed={Changed})", _config.Language, languageChanged);
|
||||||
|
|
||||||
|
if (languageChanged)
|
||||||
|
{
|
||||||
|
// Le launcher doit être relancé pour que les bindings x:Static reflètent
|
||||||
|
// 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",
|
||||||
|
MessageBoxButton.OKCancel, MessageBoxImage.Information, MessageBoxResult.OK);
|
||||||
|
if (ok == MessageBoxResult.OK)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var exe = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName;
|
||||||
|
if (!string.IsNullOrEmpty(exe))
|
||||||
|
{
|
||||||
|
var pid = Environment.ProcessId;
|
||||||
|
var cmd = $"/c (echo Wait && timeout /t 1 /nobreak > nul) & start \"\" \"{exe}\"";
|
||||||
|
Process.Start(new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = "cmd.exe",
|
||||||
|
Arguments = cmd,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
});
|
||||||
|
Application.Current.Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _logger.LogError(ex, "Restart on language change failed"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="clr-namespace:PSLauncher.App.ViewModels"
|
xmlns:vm="clr-namespace:PSLauncher.App.ViewModels"
|
||||||
|
xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
|
||||||
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
|
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
|
||||||
Title="PROSERVE Launcher"
|
Title="PROSERVE Launcher"
|
||||||
Icon="pack://application:,,,/Resources/favicon.ico"
|
Icon="pack://application:,,,/Resources/favicon.ico"
|
||||||
@@ -113,7 +114,7 @@
|
|||||||
<!-- Action button -->
|
<!-- Action button -->
|
||||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center" Margin="12,0,0,0">
|
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center" Margin="12,0,0,0">
|
||||||
<Button Style="{StaticResource PrimaryButton}"
|
<Button Style="{StaticResource PrimaryButton}"
|
||||||
Content="▶ Lancer" Padding="22,8" FontSize="13"
|
Content="{x:Static loc:Strings.ActionLaunch}" Padding="22,8" FontSize="13"
|
||||||
Command="{Binding LaunchCommand}"
|
Command="{Binding LaunchCommand}"
|
||||||
Visibility="{Binding IsInstalled, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding IsInstalled, Converter={StaticResource BoolToVisibility}}" />
|
||||||
<Button Style="{StaticResource AccentButton}"
|
<Button Style="{StaticResource AccentButton}"
|
||||||
@@ -143,13 +144,13 @@
|
|||||||
Click="OnMoreMenuClick">
|
Click="OnMoreMenuClick">
|
||||||
<Button.ContextMenu>
|
<Button.ContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<MenuItem Header="📜 Voir les release notes"
|
<MenuItem Header="{x:Static loc:Strings.MenuReleaseNotes}"
|
||||||
Command="{Binding PlacementTarget.Tag.ShowReleaseNotesCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
Command="{Binding PlacementTarget.Tag.ShowReleaseNotesCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
||||||
<MenuItem Header="📁 Ouvrir le dossier"
|
<MenuItem Header="{x:Static loc:Strings.MenuOpenFolder}"
|
||||||
Command="{Binding PlacementTarget.Tag.OpenFolderCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
Command="{Binding PlacementTarget.Tag.OpenFolderCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
||||||
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
||||||
<Separator Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
<Separator Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
||||||
<MenuItem Header="🗑 Supprimer cette version…"
|
<MenuItem Header="{x:Static loc:Strings.MenuUninstall}"
|
||||||
Command="{Binding PlacementTarget.Tag.UninstallCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
Command="{Binding PlacementTarget.Tag.UninstallCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
||||||
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
@@ -219,7 +220,7 @@
|
|||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
CornerRadius="16" Padding="14,6"
|
CornerRadius="16" Padding="14,6"
|
||||||
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
||||||
ToolTip="Voir / changer la license">
|
ToolTip="{x:Static loc:Strings.LicenseTooltip}">
|
||||||
<Border.Style>
|
<Border.Style>
|
||||||
<Style TargetType="Border">
|
<Style TargetType="Border">
|
||||||
<Setter Property="Background" Value="#2A1414" />
|
<Setter Property="Background" Value="#2A1414" />
|
||||||
@@ -283,7 +284,7 @@
|
|||||||
<StackPanel Grid.Column="2" Orientation="Horizontal"
|
<StackPanel Grid.Column="2" Orientation="Horizontal"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Center">
|
HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||||
<Button Style="{StaticResource SecondaryButton}"
|
<Button Style="{StaticResource SecondaryButton}"
|
||||||
Content="⚙ Paramètres"
|
Content="{x:Static loc:Strings.TopBarSettings}"
|
||||||
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
||||||
Command="{Binding OpenSettingsCommand}"
|
Command="{Binding OpenSettingsCommand}"
|
||||||
Margin="0,0,16,0" />
|
Margin="0,0,16,0" />
|
||||||
@@ -368,7 +369,7 @@
|
|||||||
|
|
||||||
<!-- Label "Version courante" -->
|
<!-- Label "Version courante" -->
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||||
Text="VERSION COURANTE"
|
Text="{x:Static loc:Strings.FeaturedCurrent}"
|
||||||
FontSize="11" FontWeight="Bold"
|
FontSize="11" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,0,0,4" />
|
Margin="0,0,0,4" />
|
||||||
@@ -412,7 +413,7 @@
|
|||||||
<!-- Action principale (gros bouton) -->
|
<!-- Action principale (gros bouton) -->
|
||||||
<Button Grid.Row="0" Grid.RowSpan="3" Grid.Column="1"
|
<Button Grid.Row="0" Grid.RowSpan="3" Grid.Column="1"
|
||||||
Style="{StaticResource PrimaryButton}"
|
Style="{StaticResource PrimaryButton}"
|
||||||
Content="▶ LANCER"
|
Content="{x:Static loc:Strings.ActionLaunchBig}"
|
||||||
FontSize="20" Padding="56,16"
|
FontSize="20" Padding="56,16"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Command="{Binding FeaturedVersion.LaunchCommand}"
|
Command="{Binding FeaturedVersion.LaunchCommand}"
|
||||||
@@ -454,13 +455,13 @@
|
|||||||
Click="OnMoreMenuClick">
|
Click="OnMoreMenuClick">
|
||||||
<Button.ContextMenu>
|
<Button.ContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<MenuItem Header="📜 Voir les release notes"
|
<MenuItem Header="{x:Static loc:Strings.MenuReleaseNotes}"
|
||||||
Command="{Binding PlacementTarget.Tag.ShowReleaseNotesCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
Command="{Binding PlacementTarget.Tag.ShowReleaseNotesCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
|
||||||
<MenuItem Header="📁 Ouvrir le dossier"
|
<MenuItem Header="{x:Static loc:Strings.MenuOpenFolder}"
|
||||||
Command="{Binding PlacementTarget.Tag.OpenFolderCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
Command="{Binding PlacementTarget.Tag.OpenFolderCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
||||||
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
||||||
<Separator Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
<Separator Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
||||||
<MenuItem Header="🗑 Supprimer cette version…"
|
<MenuItem Header="{x:Static loc:Strings.MenuUninstall}"
|
||||||
Command="{Binding PlacementTarget.Tag.UninstallCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
Command="{Binding PlacementTarget.Tag.UninstallCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
||||||
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding PlacementTarget.Tag.IsInstalled, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BoolToVisibility}}" />
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
@@ -477,7 +478,7 @@
|
|||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Column="0" Text="AUTRES VERSIONS"
|
<TextBlock Grid.Column="0" Text="{x:Static loc:Strings.SectionOther}"
|
||||||
FontSize="12" FontWeight="Bold"
|
FontSize="12" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
VerticalAlignment="Center" />
|
VerticalAlignment="Center" />
|
||||||
@@ -508,7 +509,7 @@
|
|||||||
<Button HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
<Button HorizontalAlignment="Left" VerticalAlignment="Bottom"
|
||||||
Margin="32,0,0,24"
|
Margin="32,0,0,24"
|
||||||
Style="{StaticResource SecondaryButton}"
|
Style="{StaticResource SecondaryButton}"
|
||||||
Content="🔄 Vérifier les MAJ"
|
Content="{x:Static loc:Strings.TopBarCheckUpdates}"
|
||||||
Command="{Binding CheckForUpdatesCommand}" />
|
Command="{Binding CheckForUpdatesCommand}" />
|
||||||
|
|
||||||
<!-- Copyright flottant en bas centré, sur une pill sombre pour rester
|
<!-- Copyright flottant en bas centré, sur une pill sombre pour rester
|
||||||
@@ -546,7 +547,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
Style="{StaticResource SecondaryButton}"
|
Style="{StaticResource SecondaryButton}"
|
||||||
Content="Annuler"
|
Content="{x:Static loc:Strings.ActionCancel}"
|
||||||
VerticalAlignment="Center" Margin="12,0,0,0"
|
VerticalAlignment="Center" Margin="12,0,0,0"
|
||||||
Command="{Binding CancelDownloadCommand}"
|
Command="{Binding CancelDownloadCommand}"
|
||||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibility}}" />
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<Window x:Class="PSLauncher.App.Views.OnboardingDialog"
|
<Window x:Class="PSLauncher.App.Views.OnboardingDialog"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
Title="Activation PROSERVE Launcher"
|
xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
|
||||||
|
Title="{x:Static loc:Strings.OnboardingTitle}"
|
||||||
Icon="pack://application:,,,/Resources/favicon.ico"
|
Icon="pack://application:,,,/Resources/favicon.ico"
|
||||||
Width="540" Height="420"
|
Width="540" Height="420"
|
||||||
MinWidth="480" MinHeight="380"
|
MinWidth="480" MinHeight="380"
|
||||||
@@ -18,17 +19,17 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Text="Activer votre license"
|
<TextBlock Grid.Row="0" Text="{x:Static loc:Strings.OnboardingHeading}"
|
||||||
FontSize="22" FontWeight="SemiBold"
|
FontSize="22" FontWeight="SemiBold"
|
||||||
Foreground="{StaticResource Brush.Text.Primary}" />
|
Foreground="{StaticResource Brush.Text.Primary}" />
|
||||||
|
|
||||||
<TextBlock Grid.Row="1"
|
<TextBlock Grid.Row="1"
|
||||||
Text="Saisis la clé fournie par ASTERION. Elle te donne accès aux téléchargements jusqu'à la date de validité associée."
|
Text="{x:Static loc:Strings.OnboardingBody}"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,8,0,18" />
|
Margin="0,8,0,18" />
|
||||||
|
|
||||||
<TextBlock Grid.Row="2" Text="Clé de license"
|
<TextBlock Grid.Row="2" Text="{x:Static loc:Strings.OnboardingLicenseKey}"
|
||||||
FontSize="12" FontWeight="Bold"
|
FontSize="12" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}" />
|
Foreground="{StaticResource Brush.Text.Secondary}" />
|
||||||
<TextBox Grid.Row="3" x:Name="KeyBox"
|
<TextBox Grid.Row="3" x:Name="KeyBox"
|
||||||
@@ -52,12 +53,12 @@
|
|||||||
|
|
||||||
<StackPanel Grid.Row="5" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,18,0,0">
|
<StackPanel Grid.Row="5" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,18,0,0">
|
||||||
<Button Style="{StaticResource SecondaryButton}"
|
<Button Style="{StaticResource SecondaryButton}"
|
||||||
Content="Plus tard"
|
Content="{x:Static loc:Strings.ActionLater}"
|
||||||
IsCancel="True"
|
IsCancel="True"
|
||||||
Margin="0,0,12,0"
|
Margin="0,0,12,0"
|
||||||
Click="OnLater" />
|
Click="OnLater" />
|
||||||
<Button Style="{StaticResource AccentButton}"
|
<Button Style="{StaticResource AccentButton}"
|
||||||
Content="Activer"
|
Content="{x:Static loc:Strings.OnboardingActivate}"
|
||||||
Padding="32,10"
|
Padding="32,10"
|
||||||
IsDefault="True"
|
IsDefault="True"
|
||||||
Click="OnActivate"
|
Click="OnActivate"
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="clr-namespace:PSLauncher.App.ViewModels"
|
xmlns:vm="clr-namespace:PSLauncher.App.ViewModels"
|
||||||
Title="Paramètres"
|
xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
|
||||||
|
Title="{x:Static loc:Strings.SettingsTitle}"
|
||||||
Icon="pack://application:,,,/Resources/favicon.ico"
|
Icon="pack://application:,,,/Resources/favicon.ico"
|
||||||
Width="640" Height="720"
|
Width="640" Height="720"
|
||||||
MinWidth="540" MinHeight="500"
|
MinWidth="540" MinHeight="500"
|
||||||
@@ -22,13 +23,36 @@
|
|||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<Border Grid.Row="0" Padding="32,24,32,16">
|
<Border Grid.Row="0" Padding="32,24,32,16">
|
||||||
<TextBlock Text="Paramètres" FontSize="22" FontWeight="SemiBold"
|
<TextBlock Text="{x:Static loc:Strings.SettingsTitle}" FontSize="22" FontWeight="SemiBold"
|
||||||
Foreground="{StaticResource Brush.Text.Primary}" />
|
Foreground="{StaticResource Brush.Text.Primary}" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Padding="32,0,32,16">
|
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Padding="32,0,32,16">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
|
|
||||||
|
<!-- Langue de l'interface -->
|
||||||
|
<Border Background="{StaticResource Brush.Bg.Card}"
|
||||||
|
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
||||||
|
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{x:Static loc:Strings.SettingsLanguage}"
|
||||||
|
FontSize="11" FontWeight="Bold"
|
||||||
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
|
Margin="0,0,0,8" />
|
||||||
|
<ComboBox ItemsSource="{Binding AvailableLanguages}"
|
||||||
|
DisplayMemberPath="Name"
|
||||||
|
SelectedValuePath="Code"
|
||||||
|
SelectedValue="{Binding Language, Mode=TwoWay}"
|
||||||
|
Background="#1A1A20"
|
||||||
|
Foreground="{StaticResource Brush.Text.Primary}"
|
||||||
|
BorderBrush="{StaticResource Brush.Border}"
|
||||||
|
BorderThickness="1" Padding="8" />
|
||||||
|
<TextBlock Text="{x:Static loc:Strings.SettingsLanguageHint}"
|
||||||
|
FontSize="11" Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
|
FontStyle="Italic" Margin="0,6,0,0" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<!-- License (en tête, bordure colorée selon état) -->
|
<!-- License (en tête, bordure colorée selon état) -->
|
||||||
<Border BorderThickness="2"
|
<Border BorderThickness="2"
|
||||||
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
||||||
@@ -83,7 +107,7 @@
|
|||||||
|
|
||||||
<!-- Header text -->
|
<!-- Header text -->
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1"
|
<TextBlock Grid.Row="0" Grid.Column="1"
|
||||||
Text="LICENSE"
|
Text="{x:Static loc:Strings.SettingsLicense}"
|
||||||
FontSize="11" FontWeight="Bold"
|
FontSize="11" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}" />
|
Foreground="{StaticResource Brush.Text.Secondary}" />
|
||||||
<TextBlock Grid.Row="1" Grid.Column="1"
|
<TextBlock Grid.Row="1" Grid.Column="1"
|
||||||
@@ -121,7 +145,7 @@
|
|||||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
||||||
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="SERVEUR"
|
<TextBlock Text="{x:Static loc:Strings.SettingsServer}"
|
||||||
FontSize="11" FontWeight="Bold"
|
FontSize="11" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,0,0,8" />
|
Margin="0,0,0,8" />
|
||||||
@@ -141,7 +165,7 @@
|
|||||||
BorderThickness="1" Padding="8" />
|
BorderThickness="1" Padding="8" />
|
||||||
<Button Grid.Column="1" Margin="8,0,0,0"
|
<Button Grid.Column="1" Margin="8,0,0,0"
|
||||||
Style="{StaticResource SecondaryButton}"
|
Style="{StaticResource SecondaryButton}"
|
||||||
Content="Tester"
|
Content="{x:Static loc:Strings.SettingsTest}"
|
||||||
Command="{Binding TestConnectionCommand}"
|
Command="{Binding TestConnectionCommand}"
|
||||||
IsEnabled="{Binding IsTestingConnection, Converter={StaticResource InverseBoolToBool}}" />
|
IsEnabled="{Binding IsTestingConnection, Converter={StaticResource InverseBoolToBool}}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -156,7 +180,7 @@
|
|||||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
||||||
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="INSTALLATION"
|
<TextBlock Text="{x:Static loc:Strings.SettingsInstallation}"
|
||||||
FontSize="11" FontWeight="Bold"
|
FontSize="11" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,0,0,8" />
|
Margin="0,0,0,8" />
|
||||||
@@ -177,7 +201,7 @@
|
|||||||
FontFamily="Consolas" />
|
FontFamily="Consolas" />
|
||||||
<Button Grid.Column="1" Margin="8,0,0,0"
|
<Button Grid.Column="1" Margin="8,0,0,0"
|
||||||
Style="{StaticResource SecondaryButton}"
|
Style="{StaticResource SecondaryButton}"
|
||||||
Content="📁 Parcourir"
|
Content="{x:Static loc:Strings.SettingsBrowse}"
|
||||||
Command="{Binding BrowseInstallRootCommand}" />
|
Command="{Binding BrowseInstallRootCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -188,7 +212,7 @@
|
|||||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
||||||
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="CACHE DE TÉLÉCHARGEMENTS"
|
<TextBlock Text="{x:Static loc:Strings.SettingsCache}"
|
||||||
FontSize="11" FontWeight="Bold"
|
FontSize="11" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,0,0,8" />
|
Margin="0,0,0,8" />
|
||||||
@@ -215,7 +239,7 @@
|
|||||||
Command="{Binding OpenCacheFolderCommand}" />
|
Command="{Binding OpenCacheFolderCommand}" />
|
||||||
<Button Grid.Column="2" Margin="8,0,0,0"
|
<Button Grid.Column="2" Margin="8,0,0,0"
|
||||||
Style="{StaticResource SecondaryButton}"
|
Style="{StaticResource SecondaryButton}"
|
||||||
Content="🗑 Vider"
|
Content="{x:Static loc:Strings.SettingsClearCache}"
|
||||||
Command="{Binding ClearCacheCommand}" />
|
Command="{Binding ClearCacheCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -226,7 +250,7 @@
|
|||||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
||||||
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="LOGS & APPLICATION"
|
<TextBlock Text="{x:Static loc:Strings.SettingsLogs}"
|
||||||
FontSize="11" FontWeight="Bold"
|
FontSize="11" FontWeight="Bold"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,0,0,8" />
|
Margin="0,0,0,8" />
|
||||||
@@ -271,12 +295,12 @@
|
|||||||
Padding="20,12">
|
Padding="20,12">
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
<Button Style="{StaticResource SecondaryButton}"
|
<Button Style="{StaticResource SecondaryButton}"
|
||||||
Content="Annuler"
|
Content="{x:Static loc:Strings.ActionCancel}"
|
||||||
IsCancel="True"
|
IsCancel="True"
|
||||||
Margin="0,0,12,0"
|
Margin="0,0,12,0"
|
||||||
Click="OnCancel" />
|
Click="OnCancel" />
|
||||||
<Button Style="{StaticResource AccentButton}"
|
<Button Style="{StaticResource AccentButton}"
|
||||||
Content="Enregistrer"
|
Content="{x:Static loc:Strings.ActionSave}"
|
||||||
Padding="32,8"
|
Padding="32,8"
|
||||||
IsDefault="True"
|
IsDefault="True"
|
||||||
Click="OnSave" />
|
Click="OnSave" />
|
||||||
|
|||||||
155
src/PSLauncher.Core/Localization/Strings.cs
Normal file
155
src/PSLauncher.Core/Localization/Strings.cs
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace PSLauncher.Core.Localization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Strings localisés du launcher. Approche statique : la langue est résolue au
|
||||||
|
/// startup (auto-détection ou setting utilisateur) puis fixée pour toute la
|
||||||
|
/// session. Tout changement de langue nécessite un redémarrage du launcher
|
||||||
|
/// (les bindings XAML x:Static ne refresh pas dynamiquement).
|
||||||
|
///
|
||||||
|
/// Langues supportées : fr (par défaut), en, zh (Simplified), th, ar.
|
||||||
|
/// Pour Arabic, FlowDirection doit aussi être basculé en RTL côté Window.
|
||||||
|
/// </summary>
|
||||||
|
public static class Strings
|
||||||
|
{
|
||||||
|
private static string _lang = "fr";
|
||||||
|
|
||||||
|
/// <summary>Code ISO 639-1 (2 lettres) actuellement actif.</summary>
|
||||||
|
public static string Lang => _lang;
|
||||||
|
|
||||||
|
/// <summary>True quand la langue actuelle s'écrit de droite à gauche.</summary>
|
||||||
|
public static bool IsRightToLeft => _lang == "ar";
|
||||||
|
|
||||||
|
/// <summary>Langues proposées au sélecteur des Settings (code → libellé natif).</summary>
|
||||||
|
public static readonly (string Code, string Name)[] Available =
|
||||||
|
{
|
||||||
|
("auto", "Automatique (langue du système)"),
|
||||||
|
("fr", "Français"),
|
||||||
|
("en", "English"),
|
||||||
|
("zh", "中文"),
|
||||||
|
("th", "ไทย"),
|
||||||
|
("ar", "العربية"),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise la langue à partir de la valeur enregistrée dans la config.
|
||||||
|
/// "auto" ou code inconnu → on prend la langue Windows si elle correspond
|
||||||
|
/// à une des langues supportées, sinon on tombe sur l'anglais.
|
||||||
|
/// </summary>
|
||||||
|
public static void Init(string? configValue)
|
||||||
|
{
|
||||||
|
var supported = new[] { "fr", "en", "zh", "th", "ar" };
|
||||||
|
var v = configValue?.Trim().ToLowerInvariant() ?? "auto";
|
||||||
|
|
||||||
|
if (v == "auto" || string.IsNullOrEmpty(v) || Array.IndexOf(supported, v) < 0)
|
||||||
|
{
|
||||||
|
// Auto-détection depuis la culture utilisateur Windows
|
||||||
|
var sys = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
|
||||||
|
v = Array.IndexOf(supported, sys) >= 0 ? sys : "en";
|
||||||
|
}
|
||||||
|
|
||||||
|
_lang = v;
|
||||||
|
// On force aussi la culture système sur cette langue (formats date / nombre)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ci = CultureInfo.GetCultureInfo(_lang);
|
||||||
|
CultureInfo.DefaultThreadCurrentCulture = ci;
|
||||||
|
CultureInfo.DefaultThreadCurrentUICulture = ci;
|
||||||
|
Thread.CurrentThread.CurrentCulture = ci;
|
||||||
|
Thread.CurrentThread.CurrentUICulture = ci;
|
||||||
|
}
|
||||||
|
catch { /* culture inconnue, on garde le défaut */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string T(string fr, string en, string zh, string th, string ar) => _lang switch
|
||||||
|
{
|
||||||
|
"en" => en,
|
||||||
|
"zh" => zh,
|
||||||
|
"th" => th,
|
||||||
|
"ar" => ar,
|
||||||
|
_ => fr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== TOP BAR ====================
|
||||||
|
public static string TopBarCheckUpdates => T("🔄 Vérifier les MAJ", "🔄 Check for updates", "🔄 检查更新", "🔄 ตรวจสอบการอัปเดต", "🔄 التحقق من التحديثات");
|
||||||
|
public static string TopBarSettings => T("⚙ Paramètres", "⚙ Settings", "⚙ 设置", "⚙ ตั้งค่า", "⚙ الإعدادات");
|
||||||
|
|
||||||
|
// ==================== BODY ====================
|
||||||
|
public static string BodyVersions => T("Versions", "Versions", "版本", "เวอร์ชัน", "النسخ");
|
||||||
|
public static string BodyVersionsHint => T(
|
||||||
|
"Lance, installe ou supprime une version. Les versions installées et celles disponibles sur le serveur cohabitent.",
|
||||||
|
"Launch, install or remove a version. Installed and available versions can coexist.",
|
||||||
|
"启动、安装或删除版本。已安装的版本与服务器上可用的版本可以共存。",
|
||||||
|
"เปิด ติดตั้ง หรือลบเวอร์ชัน เวอร์ชันที่ติดตั้งและที่มีในเซิร์ฟเวอร์อยู่ร่วมกันได้",
|
||||||
|
"تشغيل أو تثبيت أو إزالة نسخة. النسخ المثبتة والمتاحة على الخادم يمكن أن تتعايش."
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string FeaturedCurrent => T("VERSION COURANTE", "CURRENT VERSION", "当前版本", "เวอร์ชันปัจจุบัน", "النسخة الحالية");
|
||||||
|
public static string SectionOther => T("AUTRES VERSIONS", "OTHER VERSIONS", "其他版本", "เวอร์ชันอื่นๆ", "نسخ أخرى");
|
||||||
|
public static string ReleasedOn => T("Sortie le ", "Released ", "发布于 ", "เผยแพร่เมื่อ ", "صدر في ");
|
||||||
|
|
||||||
|
// ==================== STATUS BADGES ====================
|
||||||
|
public static string StatusInstalled => T("● Installée", "● Installed", "● 已安装", "● ติดตั้งแล้ว", "● مثبتة");
|
||||||
|
public static string StatusAvailable => T("○ Disponible", "○ Available", "○ 可用", "○ พร้อมใช้งาน", "○ متاحة");
|
||||||
|
public static string StatusDownloading => T("⬇ Téléchargement…", "⬇ Downloading…", "⬇ 下载中…", "⬇ กำลังดาวน์โหลด…", "⬇ جارٍ التنزيل…");
|
||||||
|
public static string StatusInstalling => T("📦 Installation…", "📦 Installing…", "📦 安装中…", "📦 กำลังติดตั้ง…", "📦 جارٍ التثبيت…");
|
||||||
|
public static string StatusUninstalling => T("🗑 Suppression…", "🗑 Uninstalling…", "🗑 卸载中…", "🗑 กำลังถอนการติดตั้ง…", "🗑 جارٍ الإزالة…");
|
||||||
|
|
||||||
|
// ==================== ACTIONS ====================
|
||||||
|
public static string ActionLaunch => T("▶ Lancer", "▶ Launch", "▶ 启动", "▶ เปิด", "▶ تشغيل");
|
||||||
|
public static string ActionLaunchBig => T("▶ LANCER", "▶ LAUNCH", "▶ 启动", "▶ เปิด", "▶ تشغيل");
|
||||||
|
public static string ActionInstall => T("⬇ Installer", "⬇ Install", "⬇ 安装", "⬇ ติดตั้ง", "⬇ تثبيت");
|
||||||
|
public static string ActionInstallBig => T("⬇ INSTALLER", "⬇ INSTALL", "⬇ 安装", "⬇ ติดตั้ง", "⬇ تثبيت");
|
||||||
|
public static string ActionCancel => T("Annuler", "Cancel", "取消", "ยกเลิก", "إلغاء");
|
||||||
|
public static string ActionLater => T("Plus tard", "Later", "稍后", "ภายหลัง", "لاحقاً");
|
||||||
|
public static string ActionSave => T("Enregistrer", "Save", "保存", "บันทึก", "حفظ");
|
||||||
|
public static string ActionClose => T("Fermer", "Close", "关闭", "ปิด", "إغلاق");
|
||||||
|
public static string ActionLicenseInsufficient => T("🔒 License insuffisante", "🔒 Insufficient license", "🔒 许可证不足", "🔒 ใบอนุญาตไม่เพียงพอ", "🔒 ترخيص غير كافٍ");
|
||||||
|
|
||||||
|
// ==================== MENU "..." ====================
|
||||||
|
public static string MenuReleaseNotes => T("📜 Voir les release notes", "📜 View release notes", "📜 查看版本说明", "📜 ดูบันทึกการเปลี่ยนแปลง", "📜 عرض ملاحظات الإصدار");
|
||||||
|
public static string MenuOpenFolder => T("📁 Ouvrir le dossier", "📁 Open folder", "📁 打开文件夹", "📁 เปิดโฟลเดอร์", "📁 فتح المجلد");
|
||||||
|
public static string MenuUninstall => T("🗑 Supprimer cette version…", "🗑 Uninstall this version…", "🗑 删除此版本…", "🗑 ถอนการติดตั้งเวอร์ชันนี้…", "🗑 إزالة هذه النسخة…");
|
||||||
|
|
||||||
|
// ==================== LICENSE BADGE ====================
|
||||||
|
public static string LicenseNone => T("Aucune license", "No license", "无许可证", "ไม่มีใบอนุญาต", "لا يوجد ترخيص");
|
||||||
|
public static string LicenseRevoked => T("Révoquée", "Revoked", "已撤销", "ถูกเพิกถอน", "تم إلغاؤه");
|
||||||
|
public static string LicenseTooltip => T("Voir / changer la license", "View / change license", "查看 / 更改许可证", "ดู / เปลี่ยนใบอนุญาต", "عرض / تغيير الترخيص");
|
||||||
|
|
||||||
|
// ==================== SETTINGS ====================
|
||||||
|
public static string SettingsTitle => T("Paramètres", "Settings", "设置", "ตั้งค่า", "الإعدادات");
|
||||||
|
public static string SettingsLicense => T("LICENSE", "LICENSE", "许可证", "ใบอนุญาต", "الترخيص");
|
||||||
|
public static string SettingsServer => T("SERVEUR", "SERVER", "服务器", "เซิร์ฟเวอร์", "الخادم");
|
||||||
|
public static string SettingsInstallation => T("INSTALLATION", "INSTALLATION", "安装", "การติดตั้ง", "التثبيت");
|
||||||
|
public static string SettingsCache => T("CACHE DE TÉLÉCHARGEMENTS", "DOWNLOAD CACHE", "下载缓存", "แคชดาวน์โหลด", "ذاكرة التخزين المؤقت للتنزيلات");
|
||||||
|
public static string SettingsLogs => T("LOGS & APPLICATION", "LOGS & APP", "日志与应用", "บันทึกและแอป", "السجلات والتطبيق");
|
||||||
|
public static string SettingsLanguage => T("LANGUE", "LANGUAGE", "语言", "ภาษา", "اللغة");
|
||||||
|
public static string SettingsLanguageHint => T(
|
||||||
|
"Le launcher redémarrera pour appliquer le changement.",
|
||||||
|
"The launcher will restart to apply the change.",
|
||||||
|
"启动器将重启以应用更改。",
|
||||||
|
"Launcher จะรีสตาร์ทเพื่อใช้การเปลี่ยนแปลง",
|
||||||
|
"سيتم إعادة تشغيل المُشغِّل لتطبيق التغيير."
|
||||||
|
);
|
||||||
|
public static string SettingsTest => T("Tester", "Test", "测试", "ทดสอบ", "اختبار");
|
||||||
|
public static string SettingsBrowse => T("📁 Parcourir", "📁 Browse", "📁 浏览", "📁 เรียกดู", "📁 استعراض");
|
||||||
|
public static string SettingsClearCache => T("🗑 Vider", "🗑 Clear", "🗑 清空", "🗑 ล้าง", "🗑 مسح");
|
||||||
|
|
||||||
|
// ==================== ONBOARDING ====================
|
||||||
|
public static string OnboardingTitle => T("Activation PROSERVE Launcher", "PROSERVE Launcher activation", "PROSERVE Launcher 激活", "เปิดใช้งาน PROSERVE Launcher", "تنشيط PROSERVE Launcher");
|
||||||
|
public static string OnboardingHeading => T("Activer votre license", "Activate your license", "激活您的许可证", "เปิดใช้งานใบอนุญาตของคุณ", "تنشيط الترخيص الخاص بك");
|
||||||
|
public static string OnboardingBody => T(
|
||||||
|
"Saisis la clé fournie par ASTERION. Elle te donne accès aux téléchargements jusqu'à la date de validité associée.",
|
||||||
|
"Enter the key provided by ASTERION. It grants you download access until the associated expiration date.",
|
||||||
|
"输入 ASTERION 提供的密钥。它授予您在关联的到期日期之前的下载权限。",
|
||||||
|
"ป้อนคีย์ที่ ASTERION ให้มา ซึ่งจะให้สิทธิ์ดาวน์โหลดจนถึงวันหมดอายุที่เกี่ยวข้อง",
|
||||||
|
"أدخل المفتاح المقدم من ASTERION. يمنحك صلاحية التنزيل حتى تاريخ انتهاء الصلاحية المرتبط."
|
||||||
|
);
|
||||||
|
public static string OnboardingLicenseKey => T("Clé de license", "License key", "许可证密钥", "คีย์ใบอนุญาต", "مفتاح الترخيص");
|
||||||
|
public static string OnboardingActivate => T("Activer", "Activate", "激活", "เปิดใช้งาน", "تنشيط");
|
||||||
|
|
||||||
|
// ==================== UPDATE ====================
|
||||||
|
public static string UpdateAvailableTitle => T("Mise à jour disponible", "Update available", "有可用更新", "มีการอัปเดต", "تحديث متاح");
|
||||||
|
public static string UpdateDownload => T("⬇ Télécharger", "⬇ Download", "⬇ 下载", "⬇ ดาวน์โหลด", "⬇ تنزيل");
|
||||||
|
}
|
||||||
@@ -6,6 +6,13 @@ public sealed class LocalConfig
|
|||||||
public string ServerBaseUrl { get; set; } = "https://example.com/PS_Launcher/api";
|
public string ServerBaseUrl { get; set; } = "https://example.com/PS_Launcher/api";
|
||||||
public string InstallRoot { get; set; } = string.Empty;
|
public string InstallRoot { get; set; } = string.Empty;
|
||||||
public string? LastLaunchedVersion { get; set; }
|
public string? LastLaunchedVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Code de langue de l'UI : "auto" (suit la langue Windows), "fr", "en",
|
||||||
|
/// "zh", "th" ou "ar". Tout changement nécessite un redémarrage du launcher.
|
||||||
|
/// </summary>
|
||||||
|
public string Language { get; set; } = "auto";
|
||||||
|
|
||||||
public LicenseConfig License { get; set; } = new();
|
public LicenseConfig License { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user