i18n: full pass + culture-aware dates/sizes + Software Update License wording
- Strings.cs : ~80 new keys covering status messages, progress detail (DL/extraction/verify), license summary, license details dialog, onboarding statuses, settings field labels, restart/cancel/quit confirmations, toasts, resume choice, copyright. Strings.FormatSize and Strings.FormatDate / FormatLongDate switch units (o/Ko vs B/KB) and pattern (dd/MM/yyyy vs M/d/yyyy vs 2026年) by active language. - License terminology renamed across UI: "License" → "License de mise à jour" / "Software Update License" to clarify it gates UPDATES, not Proserve itself. Expired/revoked dialogs now spell out "you can still download versions released before this date and launch any installed version". - "🔒 License insuffisante" → "🔒 License de mise à jour requise pour cette version" / "Valid update license needed for this version" so users understand it's a per-version eligibility check, not a global block. - All hardcoded FR strings in views (SettingsDialog labels, LicenseDetails fields, Onboarding statuses, dialog titles, copyright, window chrome tooltips, "Sortie le", etc.) replaced with x:Static loc bindings. - All FormatSize duplicates (5 places) and date format strings (8 places) delegate to Strings helpers — single source of truth for localization. - Settings dialog: License section moved to the top before Language. It's the most important info and conditions what the user can download. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using PSLauncher.Core.Localization;
|
||||||
using PSLauncher.Models;
|
using PSLauncher.Models;
|
||||||
|
|
||||||
namespace PSLauncher.App.ViewModels;
|
namespace PSLauncher.App.ViewModels;
|
||||||
@@ -11,17 +12,7 @@ public sealed class InstalledVersionViewModel
|
|||||||
public string Display => $"v{Model.Version}";
|
public string Display => $"v{Model.Version}";
|
||||||
|
|
||||||
public string Subtitle =>
|
public string Subtitle =>
|
||||||
$"{FormatSize(Model.SizeBytes)} • Installée le {Model.InstalledAt.ToLocalTime():dd/MM/yyyy}";
|
$"{Strings.FormatSize(Model.SizeBytes)} • {Strings.FormatDate(Model.InstalledAt)}";
|
||||||
|
|
||||||
private static string FormatSize(long bytes)
|
|
||||||
{
|
|
||||||
if (bytes <= 0) return "—";
|
|
||||||
string[] units = { "o", "Ko", "Mo", "Go", "To" };
|
|
||||||
double v = bytes;
|
|
||||||
int u = 0;
|
|
||||||
while (v >= 1024 && u < units.Length - 1) { v /= 1024; u++; }
|
|
||||||
return $"{v:0.#} {units[u]}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => Display;
|
public override string ToString() => Display;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,12 @@ public sealed partial class SettingsViewModel : ObservableObject
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var l = _licenseService.GetCached();
|
var l = _licenseService.GetCached();
|
||||||
if (l is null) return "Aucune license activée — clique pour saisir une clé";
|
if (l is null) return Strings.LicenseSummaryNone;
|
||||||
if (l.Status == "valid")
|
if (l.Status == "valid")
|
||||||
return $"{l.OwnerName} • valable jusqu'au {l.DownloadEntitlementUntil:dd/MM/yyyy}";
|
return Strings.LicenseSummaryValid(l.OwnerName ?? "—",
|
||||||
|
Strings.FormatDate(l.DownloadEntitlementUntil));
|
||||||
if (l.Status == "expired")
|
if (l.Status == "expired")
|
||||||
return $"{l.OwnerName} • expirée le {l.DownloadEntitlementUntil:dd/MM/yyyy}";
|
return Strings.LicenseSummaryExpired(Strings.FormatDate(l.DownloadEntitlementUntil));
|
||||||
return $"{l.OwnerName} • {l.Status}";
|
return $"{l.OwnerName} • {l.Status}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +160,7 @@ public sealed partial class SettingsViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
var dlg = new Microsoft.Win32.OpenFolderDialog
|
var dlg = new Microsoft.Win32.OpenFolderDialog
|
||||||
{
|
{
|
||||||
Title = "Choisir le dossier d'installation",
|
Title = Strings.SettingsInstallRoot,
|
||||||
InitialDirectory = Directory.Exists(InstallRoot) ? InstallRoot : Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
InitialDirectory = Directory.Exists(InstallRoot) ? InstallRoot : Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||||
};
|
};
|
||||||
if (dlg.ShowDialog() == true)
|
if (dlg.ShowDialog() == true)
|
||||||
@@ -287,12 +288,5 @@ public sealed partial class SettingsViewModel : ObservableObject
|
|||||||
catch { CacheSizeDisplay = "—"; }
|
catch { CacheSizeDisplay = "—"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string FormatSize(long bytes)
|
private static string FormatSize(long bytes) => Strings.FormatSize(bytes);
|
||||||
{
|
|
||||||
if (bytes <= 0) return "0 o";
|
|
||||||
string[] units = { "o", "Ko", "Mo", "Go", "To" };
|
|
||||||
double v = bytes; int u = 0;
|
|
||||||
while (v >= 1024 && u < units.Length - 1) { v /= 1024; u++; }
|
|
||||||
return $"{v:0.#} {units[u]}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<Window x:Class="PSLauncher.App.Views.LauncherUpdateDialog"
|
<Window x:Class="PSLauncher.App.Views.LauncherUpdateDialog"
|
||||||
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="Mise à jour du launcher"
|
xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
|
||||||
|
Title="{x:Static loc:Strings.LauncherUpdateTitle}"
|
||||||
Icon="pack://application:,,,/Resources/favicon.ico"
|
Icon="pack://application:,,,/Resources/favicon.ico"
|
||||||
Width="500" Height="320"
|
Width="500" Height="320"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Row="0"
|
<TextBlock Grid.Row="0"
|
||||||
Text="Mise à jour du launcher disponible"
|
Text="{x:Static loc:Strings.LauncherUpdateAvailable}"
|
||||||
FontSize="20" FontWeight="SemiBold"
|
FontSize="20" FontWeight="SemiBold"
|
||||||
Foreground="{StaticResource Brush.Text.Primary}" />
|
Foreground="{StaticResource Brush.Text.Primary}" />
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
<Border Grid.Row="2" Background="{StaticResource Brush.Bg.Card}"
|
<Border Grid.Row="2" Background="{StaticResource Brush.Bg.Card}"
|
||||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
||||||
CornerRadius="6" Padding="16" Margin="0,16,0,0">
|
CornerRadius="6" Padding="16" Margin="0,16,0,0">
|
||||||
<TextBlock Text="Le launcher va se mettre à jour : il téléchargera le nouveau binaire, se fermera, sera remplacé, puis se relancera automatiquement. Cela prend quelques secondes."
|
<TextBlock Text="{x:Static loc:Strings.LauncherUpdateBody}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</Border>
|
</Border>
|
||||||
@@ -41,11 +42,11 @@
|
|||||||
<StackPanel Grid.Row="3" Orientation="Horizontal"
|
<StackPanel Grid.Row="3" Orientation="Horizontal"
|
||||||
HorizontalAlignment="Right" Margin="0,18,0,0">
|
HorizontalAlignment="Right" Margin="0,18,0,0">
|
||||||
<Button Style="{StaticResource SecondaryButton}"
|
<Button Style="{StaticResource SecondaryButton}"
|
||||||
Content="Plus tard" IsCancel="True"
|
Content="{x:Static loc:Strings.ActionLater}" 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="⬇ Mettre à jour"
|
Content="{x:Static loc:Strings.LauncherUpdateNow}"
|
||||||
Padding="32,8"
|
Padding="32,8"
|
||||||
IsDefault="True"
|
IsDefault="True"
|
||||||
Click="OnUpdate" />
|
Click="OnUpdate" />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using PSLauncher.Core.Localization;
|
||||||
using PSLauncher.Models;
|
using PSLauncher.Models;
|
||||||
|
|
||||||
namespace PSLauncher.App.Views;
|
namespace PSLauncher.App.Views;
|
||||||
@@ -12,7 +13,7 @@ public partial class LauncherUpdateDialog : Window
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
VersionText.Text = $"v{currentVersion} → v{info.Version}";
|
VersionText.Text = $"v{currentVersion} → v{info.Version}";
|
||||||
SizeText.Text = info.Download.SizeBytes > 0
|
SizeText.Text = info.Download.SizeBytes > 0
|
||||||
? $"Taille : {FormatSize(info.Download.SizeBytes)}"
|
? Strings.SizeLabel(Strings.FormatSize(info.Download.SizeBytes))
|
||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,13 +30,4 @@ public partial class LauncherUpdateDialog : Window
|
|||||||
DialogResult = false;
|
DialogResult = false;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string FormatSize(long bytes)
|
|
||||||
{
|
|
||||||
if (bytes <= 0) return "—";
|
|
||||||
string[] units = { "o", "Ko", "Mo", "Go" };
|
|
||||||
double v = bytes; int u = 0;
|
|
||||||
while (v >= 1024 && u < units.Length - 1) { v /= 1024; u++; }
|
|
||||||
return $"{v:0.#} {units[u]}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Window x:Class="PSLauncher.App.Views.LicenseDetailsDialog"
|
<Window x:Class="PSLauncher.App.Views.LicenseDetailsDialog"
|
||||||
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:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
|
||||||
Title="License"
|
Title="License"
|
||||||
Icon="pack://application:,,,/Resources/favicon.ico"
|
Icon="pack://application:,,,/Resources/favicon.ico"
|
||||||
Width="500" Height="480"
|
Width="500" Height="480"
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
<ColumnDefinition Width="160" />
|
<ColumnDefinition Width="160" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Column="0" Text="Client"
|
<TextBlock Grid.Column="0" Text="{x:Static loc:Strings.LicenseDetailsClient}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
|
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
|
||||||
<TextBlock Grid.Column="1" x:Name="OwnerText"
|
<TextBlock Grid.Column="1" x:Name="OwnerText"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
@@ -56,7 +57,7 @@
|
|||||||
<ColumnDefinition Width="160" />
|
<ColumnDefinition Width="160" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Column="0" Text="Validité téléchargements"
|
<TextBlock Grid.Column="0" Text="{x:Static loc:Strings.LicenseDetailsValidity}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
|
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
|
||||||
<TextBlock Grid.Column="1" x:Name="UntilText"
|
<TextBlock Grid.Column="1" x:Name="UntilText"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
@@ -67,7 +68,7 @@
|
|||||||
<ColumnDefinition Width="160" />
|
<ColumnDefinition Width="160" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Column="0" Text="Activée le"
|
<TextBlock Grid.Column="0" Text="{x:Static loc:Strings.LicenseDetailsActivatedOn}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
|
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
|
||||||
<TextBlock Grid.Column="1" x:Name="IssuedText"
|
<TextBlock Grid.Column="1" x:Name="IssuedText"
|
||||||
Foreground="{StaticResource Brush.Text.Primary}" />
|
Foreground="{StaticResource Brush.Text.Primary}" />
|
||||||
@@ -77,7 +78,7 @@
|
|||||||
<ColumnDefinition Width="160" />
|
<ColumnDefinition Width="160" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Column="0" Text="ID machine"
|
<TextBlock Grid.Column="0" Text="{x:Static loc:Strings.LicenseDetailsMachineId}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12"
|
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12"
|
||||||
VerticalAlignment="Center" />
|
VerticalAlignment="Center" />
|
||||||
<Grid Grid.Column="1">
|
<Grid Grid.Column="1">
|
||||||
@@ -91,7 +92,7 @@
|
|||||||
TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
|
TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
|
||||||
<Button Grid.Column="1" Style="{StaticResource SecondaryButton}"
|
<Button Grid.Column="1" Style="{StaticResource SecondaryButton}"
|
||||||
Content="📋"
|
Content="📋"
|
||||||
ToolTip="Copier"
|
ToolTip="{x:Static loc:Strings.CopyTooltip}"
|
||||||
Click="OnCopyMachineId" />
|
Click="OnCopyMachineId" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -101,11 +102,11 @@
|
|||||||
<!-- Footer actions -->
|
<!-- Footer actions -->
|
||||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,18,0,0">
|
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,18,0,0">
|
||||||
<Button Style="{StaticResource SecondaryButton}"
|
<Button Style="{StaticResource SecondaryButton}"
|
||||||
Content="🗑 Désactiver la license"
|
Content="{x:Static loc:Strings.LicenseDetailsDeactivate}"
|
||||||
Click="OnDeactivate"
|
Click="OnDeactivate"
|
||||||
Margin="0,0,12,0" />
|
Margin="0,0,12,0" />
|
||||||
<Button Style="{StaticResource AccentButton}"
|
<Button Style="{StaticResource AccentButton}"
|
||||||
Content="Fermer"
|
Content="{x:Static loc:Strings.ActionClose}"
|
||||||
IsCancel="True" IsDefault="True"
|
IsCancel="True" IsDefault="True"
|
||||||
Padding="32,8"
|
Padding="32,8"
|
||||||
Click="OnClose" />
|
Click="OnClose" />
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ public partial class LicenseDetailsDialog : Window
|
|||||||
|
|
||||||
OwnerText.Text = license.OwnerName ?? "—";
|
OwnerText.Text = license.OwnerName ?? "—";
|
||||||
UntilText.Text = license.DownloadEntitlementUntil is { } until
|
UntilText.Text = license.DownloadEntitlementUntil is { } until
|
||||||
? $"jusqu'au {until.ToLocalTime():dddd dd MMMM yyyy}"
|
? Strings.FormatLongDate(until)
|
||||||
: "—";
|
: "—";
|
||||||
IssuedText.Text = license.IssuedAt is { } issued
|
IssuedText.Text = license.IssuedAt is { } issued
|
||||||
? issued.ToLocalTime().ToString("dd/MM/yyyy")
|
? Strings.FormatDate(issued)
|
||||||
: (license.ServerTime?.ToLocalTime().ToString("dd/MM/yyyy") ?? "—");
|
: Strings.FormatDate(license.ServerTime);
|
||||||
MachineIdText.Text = licenseService.GetMachineId();
|
MachineIdText.Text = licenseService.GetMachineId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,19 +43,19 @@ public partial class LicenseDetailsDialog : Window
|
|||||||
if (l.Status == "valid")
|
if (l.Status == "valid")
|
||||||
{
|
{
|
||||||
if (until is { } u && (u - DateTime.UtcNow).TotalDays < 30)
|
if (until is { } u && (u - DateTime.UtcNow).TotalDays < 30)
|
||||||
return ("⏰", "License valide", $"Expire bientôt — le {u.ToLocalTime():dd/MM/yyyy}",
|
return ("⏰", Strings.LicenseDetailsValidTitle, Strings.LicenseDetailsExpiringSoon(Strings.FormatDate(u)),
|
||||||
Color.FromRgb(0xF5, 0x9E, 0x0B), Color.FromRgb(0x3A, 0x2A, 0x0E));
|
Color.FromRgb(0xF5, 0x9E, 0x0B), Color.FromRgb(0x3A, 0x2A, 0x0E));
|
||||||
return ("✓", "License valide", "Téléchargements de nouvelles versions autorisés",
|
return ("✓", Strings.LicenseDetailsValidTitle, Strings.LicenseDetailsValidSubtitle,
|
||||||
Color.FromRgb(0x16, 0xA3, 0x4A), Color.FromRgb(0x0E, 0x2A, 0x1B));
|
Color.FromRgb(0x16, 0xA3, 0x4A), Color.FromRgb(0x0E, 0x2A, 0x1B));
|
||||||
}
|
}
|
||||||
if (l.Status == "expired")
|
if (l.Status == "expired")
|
||||||
return ("⚠", "License expirée",
|
return ("⚠", Strings.LicenseDetailsExpiredTitle,
|
||||||
until is { } u ? $"Expirée le {u.ToLocalTime():dd/MM/yyyy}" : "Plus de téléchargements possibles",
|
until is { } u ? Strings.LicenseDetailsExpiredSubtitle(Strings.FormatDate(u)) : Strings.LicenseDetailsExpiredFallback,
|
||||||
Color.FromRgb(0xEF, 0x44, 0x44), Color.FromRgb(0x2A, 0x14, 0x14));
|
Color.FromRgb(0xEF, 0x44, 0x44), Color.FromRgb(0x2A, 0x14, 0x14));
|
||||||
if (l.Status == "revoked")
|
if (l.Status == "revoked")
|
||||||
return ("🚫", "License révoquée", "Contacte ASTERION pour plus d'informations",
|
return ("🚫", Strings.LicenseDetailsRevokedTitle, Strings.LicenseDetailsRevokedSubtitle,
|
||||||
Color.FromRgb(0xEF, 0x44, 0x44), Color.FromRgb(0x2A, 0x14, 0x14));
|
Color.FromRgb(0xEF, 0x44, 0x44), Color.FromRgb(0x2A, 0x14, 0x14));
|
||||||
return ("❓", "License inconnue", l.Message ?? l.Status,
|
return ("❓", Strings.LicenseDetailsUnknownTitle, l.Message ?? l.Status,
|
||||||
Color.FromRgb(0xEF, 0x44, 0x44), Color.FromRgb(0x2A, 0x14, 0x14));
|
Color.FromRgb(0xEF, 0x44, 0x44), Color.FromRgb(0x2A, 0x14, 0x14));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,14 @@
|
|||||||
Content="{Binding InstallButtonLabel}" Padding="22,8" FontSize="13"
|
Content="{Binding InstallButtonLabel}" Padding="22,8" FontSize="13"
|
||||||
Command="{Binding InstallCommand}"
|
Command="{Binding InstallCommand}"
|
||||||
Visibility="{Binding IsRemoteOnly, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding IsRemoteOnly, Converter={StaticResource BoolToVisibility}}" />
|
||||||
|
<!-- Bouton rouge « Annuler » : visible uniquement quand on a un partial.
|
||||||
|
Permet d'abandonner le partial et repartir de zéro (avec confirmation). -->
|
||||||
|
<Button Style="{StaticResource DangerButton}"
|
||||||
|
Content="{x:Static loc:Strings.ActionCancel}"
|
||||||
|
Padding="14,8" FontSize="13" Margin="6,0,0,0"
|
||||||
|
Command="{Binding RestartFromZeroCommand}"
|
||||||
|
ToolTip="{x:Static loc:Strings.MenuRestartFromZero}"
|
||||||
|
Visibility="{Binding ShowRestartFromZero, Converter={StaticResource BoolToVisibility}}" />
|
||||||
<StackPanel Orientation="Horizontal"
|
<StackPanel Orientation="Horizontal"
|
||||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibility}}">
|
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibility}}">
|
||||||
<ProgressBar Width="140" Height="6"
|
<ProgressBar Width="140" Height="6"
|
||||||
@@ -149,6 +157,9 @@
|
|||||||
<MenuItem Header="{x:Static loc:Strings.MenuOpenFolder}"
|
<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}}" />
|
||||||
|
<MenuItem Header="{x:Static loc:Strings.MenuRestartFromZero}"
|
||||||
|
Command="{Binding PlacementTarget.Tag.RestartFromZeroCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
||||||
|
Visibility="{Binding PlacementTarget.Tag.HasResumableDownload, 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="{x:Static loc:Strings.MenuUninstall}"
|
<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}}"
|
||||||
@@ -289,15 +300,15 @@
|
|||||||
Command="{Binding OpenSettingsCommand}"
|
Command="{Binding OpenSettingsCommand}"
|
||||||
Margin="0,0,16,0" />
|
Margin="0,0,16,0" />
|
||||||
<Button Style="{StaticResource WindowControlButton}"
|
<Button Style="{StaticResource WindowControlButton}"
|
||||||
Content="—" ToolTip="Réduire"
|
Content="—" ToolTip="{x:Static loc:Strings.Minimize}"
|
||||||
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
||||||
Click="OnMinimizeClick" />
|
Click="OnMinimizeClick" />
|
||||||
<Button Style="{StaticResource WindowControlButton}"
|
<Button Style="{StaticResource WindowControlButton}"
|
||||||
Content="☐" ToolTip="Agrandir / Restaurer"
|
Content="☐" ToolTip="{x:Static loc:Strings.Maximize}"
|
||||||
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
||||||
Click="OnMaxRestoreClick" />
|
Click="OnMaxRestoreClick" />
|
||||||
<Button Style="{StaticResource WindowCloseButton}"
|
<Button Style="{StaticResource WindowCloseButton}"
|
||||||
Content="✕" ToolTip="Fermer"
|
Content="✕" ToolTip="{x:Static loc:Strings.CloseTooltip}"
|
||||||
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
shell:WindowChrome.IsHitTestVisibleInChrome="True"
|
||||||
Click="OnCloseClick" />
|
Click="OnCloseClick" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -404,7 +415,7 @@
|
|||||||
FontSize="13"
|
FontSize="13"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,8,0,0">
|
Margin="0,8,0,0">
|
||||||
<Run Text="Sortie le " />
|
<Run Text="{x:Static loc:Strings.ReleasedOn}" />
|
||||||
<Run Text="{Binding FeaturedVersion.PrimaryDate, Mode=OneWay}" />
|
<Run Text="{Binding FeaturedVersion.PrimaryDate, Mode=OneWay}" />
|
||||||
<Run Text=" • " />
|
<Run Text=" • " />
|
||||||
<Run Text="{Binding FeaturedVersion.SizeDisplay, Mode=OneWay}" />
|
<Run Text="{Binding FeaturedVersion.SizeDisplay, Mode=OneWay}" />
|
||||||
@@ -419,13 +430,23 @@
|
|||||||
Command="{Binding FeaturedVersion.LaunchCommand}"
|
Command="{Binding FeaturedVersion.LaunchCommand}"
|
||||||
Visibility="{Binding FeaturedVersion.IsInstalled, Converter={StaticResource BoolToVisibility}}" />
|
Visibility="{Binding FeaturedVersion.IsInstalled, Converter={StaticResource BoolToVisibility}}" />
|
||||||
|
|
||||||
<Button Grid.Row="0" Grid.RowSpan="3" Grid.Column="1"
|
<StackPanel Grid.Row="0" Grid.RowSpan="3" Grid.Column="1"
|
||||||
Style="{StaticResource AccentButton}"
|
Orientation="Vertical" VerticalAlignment="Center"
|
||||||
|
Visibility="{Binding FeaturedVersion.IsRemoteOnly, Converter={StaticResource BoolToVisibility}}">
|
||||||
|
<Button Style="{StaticResource AccentButton}"
|
||||||
Content="{Binding FeaturedVersion.InstallButtonLabel}"
|
Content="{Binding FeaturedVersion.InstallButtonLabel}"
|
||||||
FontSize="20" Padding="48,16"
|
FontSize="20" Padding="48,16"
|
||||||
VerticalAlignment="Center"
|
Command="{Binding FeaturedVersion.InstallCommand}" />
|
||||||
Command="{Binding FeaturedVersion.InstallCommand}"
|
<!-- Bouton rouge « Annuler » : visible uniquement quand un partial existe.
|
||||||
Visibility="{Binding FeaturedVersion.IsRemoteOnly, Converter={StaticResource BoolToVisibility}}" />
|
Permet d'abandonner et repartir de zéro (confirmation requise). -->
|
||||||
|
<Button Style="{StaticResource DangerButton}"
|
||||||
|
Content="{x:Static loc:Strings.ActionCancel}"
|
||||||
|
FontSize="13" Padding="20,8" Margin="0,8,0,0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Command="{Binding FeaturedVersion.RestartFromZeroCommand}"
|
||||||
|
ToolTip="{x:Static loc:Strings.MenuRestartFromZero}"
|
||||||
|
Visibility="{Binding FeaturedVersion.ShowRestartFromZero, Converter={StaticResource BoolToVisibility}}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Grid.RowSpan="3" Grid.Column="1"
|
<StackPanel Grid.Row="0" Grid.RowSpan="3" Grid.Column="1"
|
||||||
Orientation="Vertical" VerticalAlignment="Center" Width="220"
|
Orientation="Vertical" VerticalAlignment="Center" Width="220"
|
||||||
@@ -460,6 +481,9 @@
|
|||||||
<MenuItem Header="{x:Static loc:Strings.MenuOpenFolder}"
|
<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}}" />
|
||||||
|
<MenuItem Header="{x:Static loc:Strings.MenuRestartFromZero}"
|
||||||
|
Command="{Binding PlacementTarget.Tag.RestartFromZeroCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
|
||||||
|
Visibility="{Binding PlacementTarget.Tag.HasResumableDownload, 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="{x:Static loc:Strings.MenuUninstall}"
|
<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}}"
|
||||||
@@ -519,7 +543,7 @@
|
|||||||
Background="#A0000000"
|
Background="#A0000000"
|
||||||
CornerRadius="10"
|
CornerRadius="10"
|
||||||
Padding="10,4">
|
Padding="10,4">
|
||||||
<TextBlock Text="© 2026 ASTERION VR — Tous droits réservés"
|
<TextBlock Text="{x:Static loc:Strings.Copyright}"
|
||||||
FontSize="11"
|
FontSize="11"
|
||||||
Foreground="White" />
|
Foreground="White" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using PSLauncher.Core.Licensing;
|
using PSLauncher.Core.Licensing;
|
||||||
|
using PSLauncher.Core.Localization;
|
||||||
|
|
||||||
namespace PSLauncher.App.Views;
|
namespace PSLauncher.App.Views;
|
||||||
|
|
||||||
@@ -24,12 +25,12 @@ public partial class OnboardingDialog : Window
|
|||||||
var key = KeyBox.Text?.Trim().ToUpperInvariant() ?? string.Empty;
|
var key = KeyBox.Text?.Trim().ToUpperInvariant() ?? string.Empty;
|
||||||
if (string.IsNullOrEmpty(key) || key.Contains("XXXX"))
|
if (string.IsNullOrEmpty(key) || key.Contains("XXXX"))
|
||||||
{
|
{
|
||||||
ShowStatus("Saisis une clé valide au format PRSRV-XXXX-XXXX-XXXX-XXXX.", isError: true);
|
ShowStatus(Strings.OnboardingInvalidKey, isError: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivateButton.IsEnabled = false;
|
ActivateButton.IsEnabled = false;
|
||||||
ShowStatus("Validation en cours…", isError: false);
|
ShowStatus(Strings.OnboardingValidating, isError: false);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -38,7 +39,8 @@ public partial class OnboardingDialog : Window
|
|||||||
{
|
{
|
||||||
case "valid":
|
case "valid":
|
||||||
_licenseService.SaveCached(key, resp);
|
_licenseService.SaveCached(key, resp);
|
||||||
ShowStatus($"License activée ({resp.OwnerName}). Téléchargements autorisés jusqu'au {resp.DownloadEntitlementUntil:dd/MM/yyyy}.", isError: false);
|
ShowStatus(Strings.OnboardingActivated(resp.OwnerName ?? "—",
|
||||||
|
Strings.FormatDate(resp.DownloadEntitlementUntil)), isError: false);
|
||||||
LicenseActivated = true;
|
LicenseActivated = true;
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
Close();
|
Close();
|
||||||
@@ -46,27 +48,27 @@ public partial class OnboardingDialog : Window
|
|||||||
|
|
||||||
case "expired":
|
case "expired":
|
||||||
_licenseService.SaveCached(key, resp); // on cache quand même pour permettre de lancer les versions installées
|
_licenseService.SaveCached(key, resp); // on cache quand même pour permettre de lancer les versions installées
|
||||||
ShowStatus($"License expirée le {resp.DownloadEntitlementUntil:dd/MM/yyyy}. Tu peux toujours utiliser les versions déjà installées, mais plus en télécharger de nouvelles.", isError: true);
|
ShowStatus(Strings.OnboardingExpired(Strings.FormatDate(resp.DownloadEntitlementUntil)), isError: true);
|
||||||
LicenseActivated = true;
|
LicenseActivated = true;
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
Close();
|
Close();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case "revoked":
|
case "revoked":
|
||||||
ShowStatus("Cette license a été révoquée. Contacte ASTERION.", isError: true);
|
ShowStatus(Strings.OnboardingRevoked, isError: true);
|
||||||
break;
|
break;
|
||||||
case "machine_limit_exceeded":
|
case "machine_limit_exceeded":
|
||||||
ShowStatus(resp.Message ?? "Cette license a atteint son nombre maximum de machines.", isError: true);
|
ShowStatus(resp.Message ?? Strings.OnboardingMachineLimit, isError: true);
|
||||||
break;
|
break;
|
||||||
case "invalid":
|
case "invalid":
|
||||||
default:
|
default:
|
||||||
ShowStatus(resp.Message ?? "Clé de license inconnue.", isError: true);
|
ShowStatus(resp.Message ?? Strings.OnboardingInvalid, isError: true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ShowStatus($"Erreur de communication avec le serveur :\n{ex.Message}", isError: true);
|
ShowStatus(Strings.OnboardingServerError(ex.Message), isError: true);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<Window x:Class="PSLauncher.App.Views.ReleaseNotesViewerDialog"
|
<Window x:Class="PSLauncher.App.Views.ReleaseNotesViewerDialog"
|
||||||
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="Notes de version"
|
xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
|
||||||
|
Title="{x:Static loc:Strings.MsgBoxReleaseNotes}"
|
||||||
Icon="pack://application:,,,/Resources/favicon.ico"
|
Icon="pack://application:,,,/Resources/favicon.ico"
|
||||||
Width="640" Height="540"
|
Width="640" Height="540"
|
||||||
MinWidth="480" MinHeight="400"
|
MinWidth="480" MinHeight="400"
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
|
|
||||||
<Button Grid.Row="2"
|
<Button Grid.Row="2"
|
||||||
Style="{StaticResource SecondaryButton}"
|
Style="{StaticResource SecondaryButton}"
|
||||||
Content="Fermer"
|
Content="{x:Static loc:Strings.ActionClose}"
|
||||||
IsCancel="True"
|
IsCancel="True"
|
||||||
IsDefault="True"
|
IsDefault="True"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
|
|||||||
@@ -30,30 +30,9 @@
|
|||||||
<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 -->
|
<!-- License de mise à jour (en tête : c'est l'info la plus importante,
|
||||||
<Border Background="{StaticResource Brush.Bg.Card}"
|
elle conditionne ce que l'utilisateur peut télécharger.
|
||||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
Bordure colorée selon l'état : vert/jaune/rouge). -->
|
||||||
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) -->
|
|
||||||
<Border BorderThickness="2"
|
<Border BorderThickness="2"
|
||||||
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
CornerRadius="6" Padding="20" Margin="0,0,0,16">
|
||||||
<Border.Style>
|
<Border.Style>
|
||||||
@@ -124,7 +103,7 @@
|
|||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel Grid.Column="0">
|
<StackPanel Grid.Column="0">
|
||||||
<TextBlock Text="Identifiant machine (anonyme)"
|
<TextBlock Text="{x:Static loc:Strings.SettingsMachineId}"
|
||||||
FontSize="11"
|
FontSize="11"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}" />
|
Foreground="{StaticResource Brush.Text.Secondary}" />
|
||||||
<TextBlock Text="{Binding MachineId}"
|
<TextBlock Text="{Binding MachineId}"
|
||||||
@@ -134,12 +113,35 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
Style="{StaticResource SecondaryButton}"
|
Style="{StaticResource SecondaryButton}"
|
||||||
Content="📋 Copier"
|
Content="{x:Static loc:Strings.SettingsCopyMachineId}"
|
||||||
Command="{Binding CopyMachineIdCommand}" />
|
Command="{Binding CopyMachineIdCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<!-- 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>
|
||||||
|
|
||||||
<!-- Serveur -->
|
<!-- Serveur -->
|
||||||
<Border Background="{StaticResource Brush.Bg.Card}"
|
<Border Background="{StaticResource Brush.Bg.Card}"
|
||||||
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
|
||||||
@@ -149,7 +151,7 @@
|
|||||||
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" />
|
||||||
<TextBlock Text="URL de l'API"
|
<TextBlock Text="{x:Static loc:Strings.SettingsApiUrl}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
FontSize="12" Margin="0,0,0,4" />
|
FontSize="12" Margin="0,0,0,4" />
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -184,7 +186,7 @@
|
|||||||
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" />
|
||||||
<TextBlock Text="Dossier où sont installées les versions"
|
<TextBlock Text="{x:Static loc:Strings.SettingsInstallRoot}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
FontSize="12" Margin="0,0,0,4" />
|
FontSize="12" Margin="0,0,0,4" />
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -229,7 +231,8 @@
|
|||||||
TextTrimming="CharacterEllipsis" />
|
TextTrimming="CharacterEllipsis" />
|
||||||
<TextBlock FontSize="12"
|
<TextBlock FontSize="12"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}">
|
Foreground="{StaticResource Brush.Text.Secondary}">
|
||||||
<Run Text="Taille actuelle : " />
|
<Run Text="{x:Static loc:Strings.SettingsCacheSize}" />
|
||||||
|
<Run Text=" " />
|
||||||
<Run Text="{Binding CacheSizeDisplay}" FontWeight="SemiBold" />
|
<Run Text="{Binding CacheSizeDisplay}" FontWeight="SemiBold" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -256,10 +259,11 @@
|
|||||||
Margin="0,0,0,8" />
|
Margin="0,0,0,8" />
|
||||||
<TextBlock FontSize="13"
|
<TextBlock FontSize="13"
|
||||||
Foreground="{StaticResource Brush.Text.Primary}">
|
Foreground="{StaticResource Brush.Text.Primary}">
|
||||||
<Run Text="Version : " />
|
<Run Text="{x:Static loc:Strings.SettingsLauncherVersion}" />
|
||||||
|
<Run Text=" " />
|
||||||
<Run Text="{Binding LauncherVersion, Mode=OneWay}" FontWeight="SemiBold" />
|
<Run Text="{Binding LauncherVersion, Mode=OneWay}" FontWeight="SemiBold" />
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock Text="© 2026 ASTERION VR — Tous droits réservés"
|
<TextBlock Text="{x:Static loc:Strings.Copyright}"
|
||||||
FontSize="12"
|
FontSize="12"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,4,0,0" />
|
Margin="0,4,0,0" />
|
||||||
@@ -273,14 +277,14 @@
|
|||||||
FontFamily="Consolas" FontSize="11"
|
FontFamily="Consolas" FontSize="11"
|
||||||
Foreground="{StaticResource Brush.Text.Primary}"
|
Foreground="{StaticResource Brush.Text.Primary}"
|
||||||
TextTrimming="CharacterEllipsis" />
|
TextTrimming="CharacterEllipsis" />
|
||||||
<TextBlock Text="Logs rotation quotidienne, 10 jours conservés"
|
<TextBlock Text="{x:Static loc:Strings.SettingsCacheRotation}"
|
||||||
FontSize="12"
|
FontSize="12"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
Foreground="{StaticResource Brush.Text.Secondary}"
|
||||||
Margin="0,2,0,0" />
|
Margin="0,2,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<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="📁 Ouvrir"
|
Content="{x:Static loc:Strings.OpenButton}"
|
||||||
Command="{Binding OpenLogsFolderCommand}" />
|
Command="{Binding OpenLogsFolderCommand}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<Window x:Class="PSLauncher.App.Views.UpdateAvailableDialog"
|
<Window x:Class="PSLauncher.App.Views.UpdateAvailableDialog"
|
||||||
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="Mise à jour disponible"
|
xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
|
||||||
|
Title="{x:Static loc:Strings.UpdateAvailableTitle}"
|
||||||
Icon="pack://application:,,,/Resources/favicon.ico"
|
Icon="pack://application:,,,/Resources/favicon.ico"
|
||||||
Width="640" Height="540"
|
Width="640" Height="540"
|
||||||
MinWidth="480" MinHeight="400"
|
MinWidth="480" MinHeight="400"
|
||||||
@@ -38,12 +39,12 @@
|
|||||||
|
|
||||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,18,0,0">
|
<StackPanel Grid.Row="3" 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 PrimaryButton}"
|
<Button Style="{StaticResource PrimaryButton}"
|
||||||
Content="⬇ Télécharger"
|
Content="{x:Static loc:Strings.UpdateDownload}"
|
||||||
Padding="32,10"
|
Padding="32,10"
|
||||||
Click="OnDownload" />
|
Click="OnDownload" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using PSLauncher.Core.Localization;
|
||||||
using PSLauncher.Models;
|
using PSLauncher.Models;
|
||||||
|
|
||||||
namespace PSLauncher.App.Views;
|
namespace PSLauncher.App.Views;
|
||||||
@@ -9,10 +10,14 @@ public partial class UpdateAvailableDialog : Window
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
var sizeText = version.Download.SizeBytes > 0
|
||||||
|
? Strings.FormatSize(version.Download.SizeBytes)
|
||||||
|
: Strings.SizeUnknown;
|
||||||
|
|
||||||
DataContext = new
|
DataContext = new
|
||||||
{
|
{
|
||||||
Title = $"PROSERVE v{version.Version} disponible",
|
Title = Strings.UpdateAvailableHeading(version.Version),
|
||||||
Subtitle = $"Date de release : {version.ReleasedAt.ToLocalTime():dd MMMM yyyy} • {FormatSize(version.Download.SizeBytes)}",
|
Subtitle = Strings.UpdateAvailableSubtitle(Strings.FormatLongDate(version.ReleasedAt), sizeText),
|
||||||
ReleaseNotesDocument = MarkdownTheming.BuildThemedDocument(releaseNotesMarkdown)
|
ReleaseNotesDocument = MarkdownTheming.BuildThemedDocument(releaseNotesMarkdown)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -32,14 +37,4 @@ public partial class UpdateAvailableDialog : Window
|
|||||||
DialogResult = false;
|
DialogResult = false;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string FormatSize(long bytes)
|
|
||||||
{
|
|
||||||
if (bytes <= 0) return "taille inconnue";
|
|
||||||
string[] units = { "o", "Ko", "Mo", "Go", "To" };
|
|
||||||
double v = bytes;
|
|
||||||
int u = 0;
|
|
||||||
while (v >= 1024 && u < units.Length - 1) { v /= 1024; u++; }
|
|
||||||
return $"{v:0.#} {units[u]}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,16 @@ public static class Strings
|
|||||||
public static string ActionLater => T("Plus tard", "Later", "稍后", "ภายหลัง", "لاحقاً");
|
public static string ActionLater => T("Plus tard", "Later", "稍后", "ภายหลัง", "لاحقاً");
|
||||||
public static string ActionSave => T("Enregistrer", "Save", "保存", "บันทึก", "حفظ");
|
public static string ActionSave => T("Enregistrer", "Save", "保存", "บันทึก", "حفظ");
|
||||||
public static string ActionClose => T("Fermer", "Close", "关闭", "ปิด", "إغلاق");
|
public static string ActionClose => T("Fermer", "Close", "关闭", "ปิด", "إغلاق");
|
||||||
public static string ActionLicenseInsufficient => T("🔒 License insuffisante", "🔒 Insufficient license", "🔒 许可证不足", "🔒 ใบอนุญาตไม่เพียงพอ", "🔒 ترخيص غير كافٍ");
|
// Affiché sur le bouton install d'une version dont le minLicenseDate dépasse l'entitlement de la license.
|
||||||
|
// Concrètement : ta license expire le 2024-12-31 mais cette version a été sortie le 2025-03-15 → tu ne peux pas la télécharger.
|
||||||
|
// Tu peux toujours installer/lancer une version antérieure couverte par ta période de license.
|
||||||
|
public static string ActionLicenseInsufficient => T(
|
||||||
|
"🔒 License de mise à jour requise pour cette version",
|
||||||
|
"🔒 Valid update license needed for this version",
|
||||||
|
"🔒 此版本需要有效的更新许可证",
|
||||||
|
"🔒 เวอร์ชันนี้ต้องมีใบอนุญาตอัปเดตที่ใช้ได้",
|
||||||
|
"🔒 هذه النسخة تتطلب ترخيص تحديث صالح"
|
||||||
|
);
|
||||||
|
|
||||||
// ==================== MENU "..." ====================
|
// ==================== MENU "..." ====================
|
||||||
public static string MenuReleaseNotes => T("📜 Voir les release notes", "📜 View release notes", "📜 查看版本说明", "📜 ดูบันทึกการเปลี่ยนแปลง", "📜 عرض ملاحظات الإصدار");
|
public static string MenuReleaseNotes => T("📜 Voir les release notes", "📜 View release notes", "📜 查看版本说明", "📜 ดูบันทึกการเปลี่ยนแปลง", "📜 عرض ملاحظات الإصدار");
|
||||||
@@ -113,13 +122,18 @@ public static class Strings
|
|||||||
public static string MenuUninstall => T("🗑 Supprimer cette version…", "🗑 Uninstall this version…", "🗑 删除此版本…", "🗑 ถอนการติดตั้งเวอร์ชันนี้…", "🗑 إزالة هذه النسخة…");
|
public static string MenuUninstall => T("🗑 Supprimer cette version…", "🗑 Uninstall this version…", "🗑 删除此版本…", "🗑 ถอนการติดตั้งเวอร์ชันนี้…", "🗑 إزالة هذه النسخة…");
|
||||||
|
|
||||||
// ==================== LICENSE BADGE ====================
|
// ==================== LICENSE BADGE ====================
|
||||||
public static string LicenseNone => T("Aucune license", "No license", "无许可证", "ไม่มีใบอนุญาต", "لا يوجد ترخيص");
|
// Note : on parle de « License de mise à jour » (Software Update License) plutôt
|
||||||
|
// que de « License Proserve » : Proserve lui-même est librement utilisable une
|
||||||
|
// fois installé, la license sert UNIQUEMENT à donner accès aux téléchargements
|
||||||
|
// de nouvelles versions. Un user expiré garde l'accès à toutes les versions
|
||||||
|
// sorties pendant sa période de license + peut lancer ses versions installées.
|
||||||
|
public static string LicenseNone => T("Aucune license de MAJ", "No update license", "无更新许可证", "ไม่มีใบอนุญาตอัปเดต", "لا يوجد ترخيص تحديث");
|
||||||
public static string LicenseRevoked => T("Révoquée", "Revoked", "已撤销", "ถูกเพิกถอน", "تم إلغاؤه");
|
public static string LicenseRevoked => T("Révoquée", "Revoked", "已撤销", "ถูกเพิกถอน", "تم إلغاؤه");
|
||||||
public static string LicenseTooltip => T("Voir / changer la license", "View / change license", "查看 / 更改许可证", "ดู / เปลี่ยนใบอนุญาต", "عرض / تغيير الترخيص");
|
public static string LicenseTooltip => T("Voir / changer la license de mise à jour", "View / change update license", "查看 / 更改更新许可证", "ดู / เปลี่ยนใบอนุญาตอัปเดต", "عرض / تغيير ترخيص التحديث");
|
||||||
|
|
||||||
// ==================== SETTINGS ====================
|
// ==================== SETTINGS ====================
|
||||||
public static string SettingsTitle => T("Paramètres", "Settings", "设置", "ตั้งค่า", "الإعدادات");
|
public static string SettingsTitle => T("Paramètres", "Settings", "设置", "ตั้งค่า", "الإعدادات");
|
||||||
public static string SettingsLicense => T("LICENSE", "LICENSE", "许可证", "ใบอนุญาต", "الترخيص");
|
public static string SettingsLicense => T("LICENSE DE MISE À JOUR", "SOFTWARE UPDATE LICENSE", "软件更新许可证", "ใบอนุญาตอัปเดตซอฟต์แวร์", "ترخيص تحديث البرنامج");
|
||||||
public static string SettingsServer => T("SERVEUR", "SERVER", "服务器", "เซิร์ฟเวอร์", "الخادم");
|
public static string SettingsServer => T("SERVEUR", "SERVER", "服务器", "เซิร์ฟเวอร์", "الخادم");
|
||||||
public static string SettingsInstallation => T("INSTALLATION", "INSTALLATION", "安装", "การติดตั้ง", "التثبيت");
|
public static string SettingsInstallation => T("INSTALLATION", "INSTALLATION", "安装", "การติดตั้ง", "التثبيت");
|
||||||
public static string SettingsCache => T("CACHE DE TÉLÉCHARGEMENTS", "DOWNLOAD CACHE", "下载缓存", "แคชดาวน์โหลด", "ذاكرة التخزين المؤقت للتنزيلات");
|
public static string SettingsCache => T("CACHE DE TÉLÉCHARGEMENTS", "DOWNLOAD CACHE", "下载缓存", "แคชดาวน์โหลด", "ذاكرة التخزين المؤقت للتنزيلات");
|
||||||
@@ -138,13 +152,13 @@ public static class Strings
|
|||||||
|
|
||||||
// ==================== ONBOARDING ====================
|
// ==================== ONBOARDING ====================
|
||||||
public static string OnboardingTitle => T("Activation PROSERVE Launcher", "PROSERVE Launcher activation", "PROSERVE Launcher 激活", "เปิดใช้งาน PROSERVE Launcher", "تنشيط PROSERVE Launcher");
|
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 OnboardingHeading => T("Activer votre license de mise à jour", "Activate your software update license", "激活您的软件更新许可证", "เปิดใช้งานใบอนุญาตอัปเดตซอฟต์แวร์", "تنشيط ترخيص تحديث البرنامج");
|
||||||
public static string OnboardingBody => T(
|
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.",
|
"Saisis la clé fournie par ASTERION. Elle te donne accès aux téléchargements de toutes les versions sorties jusqu'à la date de validité associée. Une fois installées, les versions sont utilisables sans connexion.",
|
||||||
"Enter the key provided by ASTERION. It grants you download access until the associated expiration date.",
|
"Enter the key provided by ASTERION. It grants download access to all versions released until the associated expiration date. Once installed, versions can be used offline.",
|
||||||
"输入 ASTERION 提供的密钥。它授予您在关联的到期日期之前的下载权限。",
|
"输入 ASTERION 提供的密钥。它授予您在关联到期日期之前发布的所有版本的下载权限。一旦安装,版本可离线使用。",
|
||||||
"ป้อนคีย์ที่ ASTERION ให้มา ซึ่งจะให้สิทธิ์ดาวน์โหลดจนถึงวันหมดอายุที่เกี่ยวข้อง",
|
"ป้อนคีย์ที่ ASTERION ให้มา ซึ่งให้สิทธิ์ดาวน์โหลดเวอร์ชันทั้งหมดที่เผยแพร่จนถึงวันหมดอายุที่เกี่ยวข้อง เมื่อติดตั้งแล้วเวอร์ชันสามารถใช้งานได้แบบออฟไลน์",
|
||||||
"أدخل المفتاح المقدم من ASTERION. يمنحك صلاحية التنزيل حتى تاريخ انتهاء الصلاحية المرتبط."
|
"أدخل المفتاح المقدم من ASTERION. يمنح حق تنزيل جميع النسخ الصادرة حتى تاريخ انتهاء الصلاحية المرتبط. بمجرد التثبيت، يمكن استخدام النسخ دون اتصال."
|
||||||
);
|
);
|
||||||
public static string OnboardingLicenseKey => T("Clé de license", "License key", "许可证密钥", "คีย์ใบอนุญาต", "مفتاح الترخيص");
|
public static string OnboardingLicenseKey => T("Clé de license", "License key", "许可证密钥", "คีย์ใบอนุญาต", "مفتاح الترخيص");
|
||||||
public static string OnboardingActivate => T("Activer", "Activate", "激活", "เปิดใช้งาน", "تنشيط");
|
public static string OnboardingActivate => T("Activer", "Activate", "激活", "เปิดใช้งาน", "تنشيط");
|
||||||
@@ -152,6 +166,16 @@ public static class Strings
|
|||||||
// ==================== UPDATE ====================
|
// ==================== UPDATE ====================
|
||||||
public static string UpdateAvailableTitle => T("Mise à jour disponible", "Update available", "有可用更新", "มีการอัปเดต", "تحديث متاح");
|
public static string UpdateAvailableTitle => T("Mise à jour disponible", "Update available", "有可用更新", "มีการอัปเดต", "تحديث متاح");
|
||||||
public static string UpdateDownload => T("⬇ Télécharger", "⬇ Download", "⬇ 下载", "⬇ ดาวน์โหลด", "⬇ تنزيل");
|
public static string UpdateDownload => T("⬇ Télécharger", "⬇ Download", "⬇ 下载", "⬇ ดาวน์โหลด", "⬇ تنزيل");
|
||||||
|
public static string LauncherUpdateTitle => T("Mise à jour du launcher", "Launcher update", "启动器更新", "อัปเดต Launcher", "تحديث المُشغِّل");
|
||||||
|
public static string LauncherUpdateAvailable => T("Mise à jour du launcher disponible", "Launcher update available", "启动器更新可用", "มีการอัปเดต Launcher", "تحديث المُشغِّل متاح");
|
||||||
|
public static string LauncherUpdateBody => T(
|
||||||
|
"Le launcher va se mettre à jour : il téléchargera le nouveau binaire, se fermera, sera remplacé, puis se relancera automatiquement. Cela prend quelques secondes.",
|
||||||
|
"The launcher will update: it will download the new binary, close, be replaced, then restart automatically. This takes a few seconds.",
|
||||||
|
"启动器将进行更新:下载新二进制文件、关闭、替换,然后自动重新启动。这需要几秒钟。",
|
||||||
|
"Launcher จะอัปเดต: ดาวน์โหลดไฟล์ใหม่ ปิด แทนที่ แล้วรีสตาร์ทอัตโนมัติ ใช้เวลาไม่กี่วินาที",
|
||||||
|
"سيتم تحديث المُشغِّل: سينزل البرنامج الجديد، يغلق، يُستبدل، ثم يعيد التشغيل تلقائياً. يستغرق ذلك بضع ثوان."
|
||||||
|
);
|
||||||
|
public static string LauncherUpdateNow => T("⬇ Mettre à jour", "⬇ Update now", "⬇ 立即更新", "⬇ อัปเดตเดี๋ยวนี้", "⬇ تحديث الآن");
|
||||||
|
|
||||||
// ==================== MESSAGEBOX TITLES ====================
|
// ==================== MESSAGEBOX TITLES ====================
|
||||||
public static string MsgBoxError => T("Erreur", "Error", "错误", "ข้อผิดพลาด", "خطأ");
|
public static string MsgBoxError => T("Erreur", "Error", "错误", "ข้อผิดพลาด", "خطأ");
|
||||||
@@ -258,4 +282,473 @@ public static class Strings
|
|||||||
"Launcher จะรีสตาร์ทเพื่อใช้ภาษาใหม่",
|
"Launcher จะรีสตาร์ทเพื่อใช้ภาษาใหม่",
|
||||||
"سيتم إعادة تشغيل المُشغِّل لتطبيق اللغة الجديدة."
|
"سيتم إعادة تشغيل المُشغِّل لتطبيق اللغة الجديدة."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ==================== STATUS MESSAGES (footer) ====================
|
||||||
|
public static string StatusCheckingUpdates => T("Vérification des mises à jour…", "Checking for updates…", "正在检查更新…", "กำลังตรวจสอบการอัปเดต…", "جارٍ التحقق من التحديثات…");
|
||||||
|
public static string StatusNoRemote => T("Aucune version distante trouvée", "No remote version found", "未找到远程版本", "ไม่พบเวอร์ชันระยะไกล", "لم يتم العثور على نسخة عن بُعد");
|
||||||
|
public static string StatusDownloadCancelled => T("Téléchargement annulé", "Download canceled", "下载已取消", "ยกเลิกการดาวน์โหลด", "تم إلغاء التنزيل");
|
||||||
|
public static string StatusDownloadingLauncher => T("Téléchargement du nouveau launcher…", "Downloading new launcher…", "正在下载新启动器…", "กำลังดาวน์โหลด Launcher ใหม่…", "جارٍ تنزيل المُشغِّل الجديد…");
|
||||||
|
public static string StatusLauncherUpdating => T(
|
||||||
|
"Mise à jour du launcher en cours… le launcher va se relancer.",
|
||||||
|
"Launcher updating… it will restart.",
|
||||||
|
"启动器正在更新…即将重启。",
|
||||||
|
"Launcher กำลังอัปเดต… จะรีสตาร์ท",
|
||||||
|
"جارٍ تحديث المُشغِّل… سيتم إعادة تشغيله."
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusError(string detail) => T(
|
||||||
|
$"Erreur : {detail}",
|
||||||
|
$"Error: {detail}",
|
||||||
|
$"错误:{detail}",
|
||||||
|
$"ข้อผิดพลาด: {detail}",
|
||||||
|
$"خطأ: {detail}"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusSelfUpdateError(string detail) => T(
|
||||||
|
$"Erreur self-update : {detail}",
|
||||||
|
$"Self-update error: {detail}",
|
||||||
|
$"自更新错误:{detail}",
|
||||||
|
$"ข้อผิดพลาดอัปเดตตัวเอง: {detail}",
|
||||||
|
$"خطأ في التحديث الذاتي: {detail}"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusUpToDate(string version) => T(
|
||||||
|
$"À jour (v{version})",
|
||||||
|
$"Up to date (v{version})",
|
||||||
|
$"已是最新(v{version})",
|
||||||
|
$"เป็นเวอร์ชันล่าสุด (v{version})",
|
||||||
|
$"محدّثة (v{version})"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusNewAvailable(string version) => T(
|
||||||
|
$"Nouvelle version disponible : v{version}",
|
||||||
|
$"New version available: v{version}",
|
||||||
|
$"有新版本可用:v{version}",
|
||||||
|
$"มีเวอร์ชันใหม่: v{version}",
|
||||||
|
$"نسخة جديدة متاحة: v{version}"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusDownloadingVersion(string version) => T(
|
||||||
|
$"Téléchargement v{version}…",
|
||||||
|
$"Downloading v{version}…",
|
||||||
|
$"正在下载 v{version}…",
|
||||||
|
$"กำลังดาวน์โหลด v{version}…",
|
||||||
|
$"جارٍ تنزيل v{version}…"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusInstallingVersion(string version) => T(
|
||||||
|
$"Installation v{version}…",
|
||||||
|
$"Installing v{version}…",
|
||||||
|
$"正在安装 v{version}…",
|
||||||
|
$"กำลังติดตั้ง v{version}…",
|
||||||
|
$"جارٍ تثبيت v{version}…"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusInstalledSuccess(string version) => T(
|
||||||
|
$"v{version} installée avec succès",
|
||||||
|
$"v{version} installed successfully",
|
||||||
|
$"v{version} 安装成功",
|
||||||
|
$"ติดตั้ง v{version} สำเร็จ",
|
||||||
|
$"تم تثبيت v{version} بنجاح"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusUninstallingVersion(string version) => T(
|
||||||
|
$"Suppression v{version}…",
|
||||||
|
$"Uninstalling v{version}…",
|
||||||
|
$"正在卸载 v{version}…",
|
||||||
|
$"กำลังถอน v{version}…",
|
||||||
|
$"جارٍ إزالة v{version}…"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusUninstalledVersion(string version) => T(
|
||||||
|
$"v{version} supprimée",
|
||||||
|
$"v{version} uninstalled",
|
||||||
|
$"v{version} 已卸载",
|
||||||
|
$"ถอน v{version} แล้ว",
|
||||||
|
$"تمت إزالة v{version}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== PROGRESS DETAIL ====================
|
||||||
|
public static string ProgressLauncherDl(string version, string done, string total) => T(
|
||||||
|
$"⬇ Launcher v{version} : {done} / {total}",
|
||||||
|
$"⬇ Launcher v{version}: {done} / {total}",
|
||||||
|
$"⬇ 启动器 v{version}:{done} / {total}",
|
||||||
|
$"⬇ Launcher v{version}: {done} / {total}",
|
||||||
|
$"⬇ المُشغِّل v{version}: {done} / {total}"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ProgressExtraction(string version, long entriesDone, long entriesTotal, string bytesDone, string bytesTotal) => T(
|
||||||
|
$"Extraction v{version} : {entriesDone}/{entriesTotal} fichiers ({bytesDone} / {bytesTotal})",
|
||||||
|
$"Extracting v{version}: {entriesDone}/{entriesTotal} files ({bytesDone} / {bytesTotal})",
|
||||||
|
$"正在解压 v{version}:{entriesDone}/{entriesTotal} 文件 ({bytesDone} / {bytesTotal})",
|
||||||
|
$"กำลังแตก v{version}: {entriesDone}/{entriesTotal} ไฟล์ ({bytesDone} / {bytesTotal})",
|
||||||
|
$"جارٍ فك v{version}: {entriesDone}/{entriesTotal} ملف ({bytesDone} / {bytesTotal})"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusVerifyingIntegrity(string version) => T(
|
||||||
|
$"Vérification de l'intégrité v{version}…",
|
||||||
|
$"Verifying integrity of v{version}…",
|
||||||
|
$"正在校验 v{version} 的完整性…",
|
||||||
|
$"กำลังตรวจสอบความถูกต้อง v{version}…",
|
||||||
|
$"جارٍ التحقق من سلامة v{version}…"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ProgressVerifying(string version, int percent) => T(
|
||||||
|
$"🔍 Vérification SHA-256 v{version} : {percent}%",
|
||||||
|
$"🔍 SHA-256 verification v{version}: {percent}%",
|
||||||
|
$"🔍 SHA-256 校验 v{version}:{percent}%",
|
||||||
|
$"🔍 ตรวจสอบ SHA-256 v{version}: {percent}%",
|
||||||
|
$"🔍 التحقق من SHA-256 v{version}: {percent}%"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string StatusPreparingDownload(string version) => T(
|
||||||
|
$"Préparation du téléchargement v{version}…",
|
||||||
|
$"Preparing download for v{version}…",
|
||||||
|
$"正在准备 v{version} 的下载…",
|
||||||
|
$"กำลังเตรียมการดาวน์โหลด v{version}…",
|
||||||
|
$"جارٍ تحضير تنزيل v{version}…"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== CONFIRM DIALOGS ====================
|
||||||
|
public static string MsgCancelDownloadConfirm(string version) => T(
|
||||||
|
$"Annuler le téléchargement de v{version} ?\n\nLa progression sera conservée — tu pourras reprendre plus tard.",
|
||||||
|
$"Cancel the download of v{version}?\n\nProgress will be kept — you'll be able to resume later.",
|
||||||
|
$"取消 v{version} 的下载?\n\n进度将被保留,您稍后可以继续。",
|
||||||
|
$"ยกเลิกการดาวน์โหลด v{version}?\n\nความคืบหน้าจะถูกบันทึกไว้ คุณสามารถดำเนินการต่อได้ภายหลัง",
|
||||||
|
$"إلغاء تنزيل v{version}؟\n\nسيتم الاحتفاظ بالتقدم — يمكنك الاستئناف لاحقاً."
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string MsgRestartDownloadConfirm(string version, string partialSize) => T(
|
||||||
|
$"Recommencer le téléchargement de v{version} depuis zéro ?\n\nLe fichier partiel ({partialSize}) sera supprimé. Cette action est irréversible.",
|
||||||
|
$"Restart the download of v{version} from scratch?\n\nThe partial file ({partialSize}) will be deleted. This is irreversible.",
|
||||||
|
$"从头开始重新下载 v{version}?\n\n部分文件 ({partialSize}) 将被删除。此操作不可逆。",
|
||||||
|
$"เริ่มดาวน์โหลด v{version} ใหม่ตั้งแต่ต้น?\n\nไฟล์บางส่วน ({partialSize}) จะถูกลบ การกระทำนี้ย้อนกลับไม่ได้",
|
||||||
|
$"إعادة تنزيل v{version} من البداية؟\n\nسيتم حذف الملف الجزئي ({partialSize}). هذا الإجراء لا رجعة فيه."
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string MsgQuitWhileDownloadingConfirm(string version) => T(
|
||||||
|
$"Un téléchargement est en cours (v{version}).\n\nQuitter le launcher ? La progression sera conservée pour reprise au prochain lancement.",
|
||||||
|
$"A download is in progress (v{version}).\n\nQuit the launcher? Progress will be kept for resume on next launch.",
|
||||||
|
$"下载正在进行 (v{version})。\n\n要退出启动器吗?进度将被保留,下次启动时可继续。",
|
||||||
|
$"การดาวน์โหลดกำลังดำเนินอยู่ (v{version})\n\nออกจาก Launcher? ความคืบหน้าจะถูกเก็บไว้สำหรับการดำเนินการต่อในการเปิดครั้งถัดไป",
|
||||||
|
$"يوجد تنزيل قيد التنفيذ (v{version}).\n\nمغادرة المُشغِّل؟ سيتم الاحتفاظ بالتقدم للاستئناف في التشغيل التالي."
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string MsgBoxQuit => T("Quitter ?", "Quit?", "退出?", "ออก?", "خروج؟");
|
||||||
|
public static string MsgBoxCancelDl => T("Annuler le DL ?", "Cancel download?", "取消下载?", "ยกเลิกการดาวน์โหลด?", "إلغاء التنزيل؟");
|
||||||
|
public static string MsgBoxRestartDl => T("Recommencer ?", "Restart?", "重新开始?", "เริ่มใหม่?", "إعادة البدء؟");
|
||||||
|
|
||||||
|
public static string MenuRestartFromZero => T(
|
||||||
|
"🔄 Recommencer depuis zéro…",
|
||||||
|
"🔄 Restart from scratch…",
|
||||||
|
"🔄 从头开始…",
|
||||||
|
"🔄 เริ่มใหม่ตั้งแต่ต้น…",
|
||||||
|
"🔄 البدء من جديد…"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== RESUME-OR-RESTART DIALOG ====================
|
||||||
|
public static string ResumeDialogTitle => T(
|
||||||
|
"Téléchargement interrompu",
|
||||||
|
"Download interrupted",
|
||||||
|
"下载已中断",
|
||||||
|
"การดาวน์โหลดถูกขัดจังหวะ",
|
||||||
|
"تم إيقاف التنزيل"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ResumeDialogHeading(string version) => T(
|
||||||
|
$"Que faire pour v{version} ?",
|
||||||
|
$"What to do for v{version}?",
|
||||||
|
$"v{version} 怎么办?",
|
||||||
|
$"จะทำอะไรกับ v{version}?",
|
||||||
|
$"ماذا تفعل لـ v{version}؟"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ResumeDialogBody(string done, string total, int percent) => T(
|
||||||
|
$"Un téléchargement précédent a été interrompu à {done} sur {total} ({percent}%).",
|
||||||
|
$"A previous download was interrupted at {done} of {total} ({percent}%).",
|
||||||
|
$"上一次下载在 {done}/{total} ({percent}%) 时中断。",
|
||||||
|
$"การดาวน์โหลดครั้งก่อนถูกขัดจังหวะที่ {done}/{total} ({percent}%)",
|
||||||
|
$"تم إيقاف تنزيل سابق عند {done}/{total} ({percent}%)."
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ResumeDialogResumeButton(int percent) => T(
|
||||||
|
$"▶ Reprendre depuis {percent}%",
|
||||||
|
$"▶ Resume from {percent}%",
|
||||||
|
$"▶ 从 {percent}% 继续",
|
||||||
|
$"▶ ดำเนินการต่อจาก {percent}%",
|
||||||
|
$"▶ استئناف من {percent}%"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ResumeDialogResumeHint => T(
|
||||||
|
"Le téléchargement reprendra là où il s'était arrêté. Aucun byte ne sera re-téléchargé.",
|
||||||
|
"The download will continue from where it stopped. No bytes will be re-downloaded.",
|
||||||
|
"下载将从中断处继续。不会重新下载任何字节。",
|
||||||
|
"การดาวน์โหลดจะดำเนินต่อจากจุดที่หยุดไว้ จะไม่มีการดาวน์โหลดซ้ำ",
|
||||||
|
"سيستمر التنزيل من حيث توقف. لن يتم إعادة تنزيل أي بايت."
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ResumeDialogRestartButton => T(
|
||||||
|
"🔄 Recommencer depuis zéro",
|
||||||
|
"🔄 Restart from scratch",
|
||||||
|
"🔄 从头开始",
|
||||||
|
"🔄 เริ่มใหม่ตั้งแต่ต้น",
|
||||||
|
"🔄 البدء من جديد"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string ResumeDialogRestartHint(string done) => T(
|
||||||
|
$"Le fichier partiel ({done}) sera supprimé et le téléchargement repartira de zéro.",
|
||||||
|
$"The partial file ({done}) will be deleted and the download will restart from zero.",
|
||||||
|
$"部分文件 ({done}) 将被删除,下载将从零开始。",
|
||||||
|
$"ไฟล์บางส่วน ({done}) จะถูกลบและจะเริ่มดาวน์โหลดใหม่ตั้งแต่ต้น",
|
||||||
|
$"سيتم حذف الملف الجزئي ({done}) وسيُعاد التنزيل من الصفر."
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== LICENSE SUMMARY (top bar badge text) ====================
|
||||||
|
public static string LicenseSummaryNone => LicenseNone;
|
||||||
|
public static string LicenseSummaryRevoked => LicenseRevoked;
|
||||||
|
|
||||||
|
public static string LicenseSummaryExpired(string date) => T(
|
||||||
|
$"Expirée le {date}",
|
||||||
|
$"Expired on {date}",
|
||||||
|
$"于 {date} 过期",
|
||||||
|
$"หมดอายุเมื่อ {date}",
|
||||||
|
$"انتهت في {date}"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string LicenseSummaryValid(string owner, string date) => T(
|
||||||
|
$"{owner} • exp. {date}",
|
||||||
|
$"{owner} • exp. {date}",
|
||||||
|
$"{owner} • 到期 {date}",
|
||||||
|
$"{owner} • หมดอายุ {date}",
|
||||||
|
$"{owner} • تنتهي {date}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== ROW STATE LABELS ====================
|
||||||
|
// (déjà définies plus haut : StatusInstalled, StatusAvailable, StatusDownloading, StatusInstalling, StatusUninstalling)
|
||||||
|
|
||||||
|
// ==================== INSTALL BUTTON LABEL VARIANTS ====================
|
||||||
|
public static string ResumeButton(int percent) => T(
|
||||||
|
$"↻ Reprendre ({percent}%)",
|
||||||
|
$"↻ Resume ({percent}%)",
|
||||||
|
$"↻ 恢复 ({percent}%)",
|
||||||
|
$"↻ ดำเนินการต่อ ({percent}%)",
|
||||||
|
$"↻ استئناف ({percent}%)"
|
||||||
|
);
|
||||||
|
public static string ResumeButtonNoPercent => T("↻ Reprendre", "↻ Resume", "↻ 恢复", "↻ ดำเนินการต่อ", "↻ استئناف");
|
||||||
|
|
||||||
|
// ==================== LICENSE DETAILS DIALOG ====================
|
||||||
|
public static string LicenseDetailsValidTitle => T("License de mise à jour valide", "Valid update license", "更新许可证有效", "ใบอนุญาตอัปเดตใช้ได้", "ترخيص التحديث صالح");
|
||||||
|
public static string LicenseDetailsValidSubtitle => T(
|
||||||
|
"Toutes les versions sont téléchargeables tant que ta license n'est pas dépassée.",
|
||||||
|
"All versions are downloadable while your license is current.",
|
||||||
|
"您的许可证有效期内可以下载所有版本。",
|
||||||
|
"ดาวน์โหลดได้ทุกเวอร์ชันตราบใดที่ใบอนุญาตยังใช้งานได้",
|
||||||
|
"يمكن تنزيل جميع النسخ طالما ترخيصك ساري."
|
||||||
|
);
|
||||||
|
public static string LicenseDetailsExpiringSoon(string date) => T(
|
||||||
|
$"Expire bientôt — le {date}",
|
||||||
|
$"Expiring soon — {date}",
|
||||||
|
$"即将过期 — {date}",
|
||||||
|
$"กำลังหมดอายุ — {date}",
|
||||||
|
$"تنتهي قريباً — {date}"
|
||||||
|
);
|
||||||
|
public static string LicenseDetailsExpiredTitle => T("License de mise à jour expirée", "Update license expired", "更新许可证已过期", "ใบอนุญาตอัปเดตหมดอายุ", "انتهى ترخيص التحديث");
|
||||||
|
public static string LicenseDetailsExpiredSubtitle(string date) => T(
|
||||||
|
$"Expirée le {date}. Tu peux encore télécharger les versions sorties avant cette date, et lancer toutes les versions installées.",
|
||||||
|
$"Expired on {date}. You can still download versions released before that date and launch any installed version.",
|
||||||
|
$"于 {date} 过期。您仍可下载该日期之前发布的版本,并运行任何已安装的版本。",
|
||||||
|
$"หมดอายุเมื่อ {date} คุณยังคงดาวน์โหลดเวอร์ชันที่เผยแพร่ก่อนวันที่นั้นและเปิดเวอร์ชันที่ติดตั้งแล้วทุกเวอร์ชัน",
|
||||||
|
$"انتهت في {date}. لا يزال بإمكانك تنزيل النسخ الصادرة قبل هذا التاريخ وتشغيل أي نسخة مثبتة."
|
||||||
|
);
|
||||||
|
public static string LicenseDetailsExpiredFallback => T(
|
||||||
|
"Plus de nouveaux téléchargements possibles. Les versions installées restent utilisables.",
|
||||||
|
"No new downloads available. Installed versions remain usable.",
|
||||||
|
"无法下载新版本。已安装的版本仍可使用。",
|
||||||
|
"ไม่สามารถดาวน์โหลดเวอร์ชันใหม่ได้ เวอร์ชันที่ติดตั้งแล้วยังใช้งานได้",
|
||||||
|
"لا يمكن إجراء تنزيلات جديدة. تظل النسخ المثبتة قابلة للاستخدام."
|
||||||
|
);
|
||||||
|
public static string LicenseDetailsRevokedTitle => T("License de mise à jour révoquée", "Update license revoked", "更新许可证已撤销", "ใบอนุญาตอัปเดตถูกเพิกถอน", "تم إلغاء ترخيص التحديث");
|
||||||
|
public static string LicenseDetailsRevokedSubtitle => T("Contacte ASTERION pour plus d'informations", "Contact ASTERION for more information", "请联系 ASTERION 了解详情", "ติดต่อ ASTERION สำหรับข้อมูลเพิ่มเติม", "اتصل بـ ASTERION لمزيد من المعلومات");
|
||||||
|
public static string LicenseDetailsUnknownTitle => T("License inconnue", "Unknown license", "未知许可证", "ใบอนุญาตที่ไม่รู้จัก", "ترخيص غير معروف");
|
||||||
|
|
||||||
|
// ==================== ONBOARDING STATUS ====================
|
||||||
|
public static string OnboardingInvalidKey => T(
|
||||||
|
"Saisis une clé valide au format PRSRV-XXXX-XXXX-XXXX-XXXX.",
|
||||||
|
"Enter a valid key (format PRSRV-XXXX-XXXX-XXXX-XXXX).",
|
||||||
|
"输入有效的密钥(格式 PRSRV-XXXX-XXXX-XXXX-XXXX)。",
|
||||||
|
"ป้อนคีย์ที่ถูกต้อง (รูปแบบ PRSRV-XXXX-XXXX-XXXX-XXXX)",
|
||||||
|
"أدخل مفتاحًا صالحًا (تنسيق PRSRV-XXXX-XXXX-XXXX-XXXX)."
|
||||||
|
);
|
||||||
|
public static string OnboardingValidating => T(
|
||||||
|
"Validation en cours…", "Validating…", "正在验证…", "กำลังตรวจสอบ…", "جارٍ التحقق…"
|
||||||
|
);
|
||||||
|
public static string OnboardingActivated(string owner, string date) => T(
|
||||||
|
$"License activée ({owner}). Téléchargements autorisés jusqu'au {date}.",
|
||||||
|
$"License activated ({owner}). Downloads allowed until {date}.",
|
||||||
|
$"许可证已激活({owner})。下载授权至 {date}。",
|
||||||
|
$"เปิดใช้งานใบอนุญาต ({owner}) ดาวน์โหลดได้ถึง {date}",
|
||||||
|
$"تم تنشيط الترخيص ({owner}). التنزيلات مسموحة حتى {date}."
|
||||||
|
);
|
||||||
|
public static string OnboardingExpired(string date) => T(
|
||||||
|
$"License de mise à jour expirée le {date}. Tu peux encore télécharger les versions sorties avant cette date et lancer toutes les versions installées. Pour accéder aux versions plus récentes, contacte ASTERION pour renouveler.",
|
||||||
|
$"Update license expired on {date}. You can still download versions released before that date and launch any installed version. To access newer versions, contact ASTERION to renew.",
|
||||||
|
$"更新许可证于 {date} 过期。您仍可下载该日期之前发布的版本,并运行任何已安装的版本。如需访问更新版本,请联系 ASTERION 续订。",
|
||||||
|
$"ใบอนุญาตอัปเดตหมดอายุเมื่อ {date} คุณยังคงดาวน์โหลดเวอร์ชันที่เผยแพร่ก่อนวันที่นั้นและเปิดเวอร์ชันที่ติดตั้งแล้วทุกเวอร์ชัน หากต้องการเข้าถึงเวอร์ชันใหม่กว่า ติดต่อ ASTERION เพื่อต่ออายุ",
|
||||||
|
$"انتهى ترخيص التحديث في {date}. لا يزال بإمكانك تنزيل النسخ الصادرة قبل هذا التاريخ وتشغيل أي نسخة مثبتة. للوصول إلى نسخ أحدث، اتصل بـ ASTERION للتجديد."
|
||||||
|
);
|
||||||
|
public static string OnboardingRevoked => T(
|
||||||
|
"Cette license a été révoquée. Contacte ASTERION.",
|
||||||
|
"This license has been revoked. Contact ASTERION.",
|
||||||
|
"此许可证已被撤销。请联系 ASTERION。",
|
||||||
|
"ใบอนุญาตนี้ถูกเพิกถอน ติดต่อ ASTERION",
|
||||||
|
"تم إلغاء هذا الترخيص. اتصل بـ ASTERION."
|
||||||
|
);
|
||||||
|
public static string OnboardingMachineLimit => T(
|
||||||
|
"Cette license a atteint son nombre maximum de machines.",
|
||||||
|
"This license has reached its maximum number of machines.",
|
||||||
|
"此许可证已达到最大机器数。",
|
||||||
|
"ใบอนุญาตถึงจำนวนเครื่องสูงสุดแล้ว",
|
||||||
|
"وصل هذا الترخيص إلى الحد الأقصى لعدد الأجهزة."
|
||||||
|
);
|
||||||
|
public static string OnboardingInvalid => T(
|
||||||
|
"Clé de license inconnue.",
|
||||||
|
"Unknown license key.",
|
||||||
|
"未知的许可证密钥。",
|
||||||
|
"คีย์ใบอนุญาตที่ไม่รู้จัก",
|
||||||
|
"مفتاح ترخيص غير معروف."
|
||||||
|
);
|
||||||
|
public static string OnboardingServerError(string detail) => T(
|
||||||
|
$"Erreur de communication avec le serveur :\n{detail}",
|
||||||
|
$"Server communication error:\n{detail}",
|
||||||
|
$"与服务器通信错误:\n{detail}",
|
||||||
|
$"การสื่อสารกับเซิร์ฟเวอร์ผิดพลาด:\n{detail}",
|
||||||
|
$"خطأ في الاتصال بالخادم:\n{detail}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== SETTINGS LABELS ====================
|
||||||
|
public static string SettingsApiUrl => T("URL de l'API", "API URL", "API 地址", "URL ของ API", "عنوان API");
|
||||||
|
public static string SettingsInstallRoot => T("Dossier où sont installées les versions", "Folder where versions are installed", "版本安装的文件夹", "โฟลเดอร์สำหรับติดตั้งเวอร์ชัน", "المجلد الذي تُثبَّت فيه النسخ");
|
||||||
|
public static string SettingsLicenseStatus => T("Statut", "Status", "状态", "สถานะ", "الحالة");
|
||||||
|
public static string SettingsMachineId => T("Identifiant machine (anonyme)", "Machine ID (anonymous)", "机器 ID(匿名)", "ID เครื่อง (ไม่ระบุตัวตน)", "معرّف الجهاز (مجهول)");
|
||||||
|
public static string SettingsCopyMachineId => T("📋 Copier", "📋 Copy", "📋 复制", "📋 คัดลอก", "📋 نسخ");
|
||||||
|
public static string SettingsCacheSize => T("Taille actuelle :", "Current size:", "当前大小:", "ขนาดปัจจุบัน:", "الحجم الحالي:");
|
||||||
|
public static string SettingsCacheRotation => T("Logs rotation quotidienne, 10 jours conservés", "Daily log rotation, 10 days kept", "日志每日轮换,保留 10 天", "หมุนเวียนบันทึกรายวัน เก็บ 10 วัน", "تدوير السجل يومياً، الاحتفاظ 10 أيام");
|
||||||
|
public static string SettingsLauncherVersion => T("Version :", "Version:", "版本:", "เวอร์ชัน:", "النسخة:");
|
||||||
|
public static string SettingsDeactivate => T("Désactiver la license sur cette machine", "Deactivate license on this machine", "在此机器上停用许可证", "ปิดใช้งานใบอนุญาตบนเครื่องนี้", "إلغاء تنشيط الترخيص على هذا الجهاز");
|
||||||
|
|
||||||
|
// ==================== LICENSE DETAILS DIALOG LABELS ====================
|
||||||
|
public static string LicenseDetailsClient => T("Client", "Customer", "客户", "ลูกค้า", "العميل");
|
||||||
|
public static string LicenseDetailsValidity => T("Validité téléchargements", "Download validity", "下载有效期", "ระยะเวลาดาวน์โหลด", "صلاحية التنزيل");
|
||||||
|
public static string LicenseDetailsActivatedOn => T("Activée le", "Activated on", "激活日期", "เปิดใช้งานเมื่อ", "تم التنشيط في");
|
||||||
|
public static string LicenseDetailsMachineId => T("ID machine", "Machine ID", "机器 ID", "ID เครื่อง", "معرّف الجهاز");
|
||||||
|
public static string LicenseDetailsDeactivate => T("🗑 Désactiver la license", "🗑 Deactivate license", "🗑 停用许可证", "🗑 ปิดใช้งานใบอนุญาต", "🗑 إلغاء تنشيط الترخيص");
|
||||||
|
|
||||||
|
// ==================== EMPTY STATE ====================
|
||||||
|
public static string EmptyHint(string installRoot) => T(
|
||||||
|
$"Aucune version locale ni distante.\nClique « Vérifier les MAJ » pour récupérer le catalogue depuis le serveur, ou place un dossier « PROSERVE v{{X.Y.Z}} » contenant PROSERVE_UE_5_5.exe dans :\n{installRoot}",
|
||||||
|
$"No local or remote version.\nClick « Check for updates » to fetch the catalog from the server, or place a folder « PROSERVE v{{X.Y.Z}} » containing PROSERVE_UE_5_5.exe in:\n{installRoot}",
|
||||||
|
$"未找到本地或远程版本。\n点击「检查更新」以从服务器获取目录,或将包含 PROSERVE_UE_5_5.exe 的「PROSERVE v{{X.Y.Z}}」文件夹放置在:\n{installRoot}",
|
||||||
|
$"ไม่พบเวอร์ชันในเครื่องหรือบนเซิร์ฟเวอร์\nคลิก « ตรวจสอบการอัปเดต » เพื่อดึงแคตตาล็อกจากเซิร์ฟเวอร์ หรือวางโฟลเดอร์ « PROSERVE v{{X.Y.Z}} » ที่มี PROSERVE_UE_5_5.exe ใน:\n{installRoot}",
|
||||||
|
$"لا توجد نسخة محلية أو عن بُعد.\nانقر « التحقق من التحديثات » لجلب الكتالوج من الخادم، أو ضع مجلداً « PROSERVE v{{X.Y.Z}} » يحتوي على PROSERVE_UE_5_5.exe في:\n{installRoot}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== TOAST NOTIFICATIONS ====================
|
||||||
|
public static string ToastInstallSuccessTitle => T("Installation terminée", "Installation complete", "安装完成", "ติดตั้งเสร็จแล้ว", "اكتمل التثبيت");
|
||||||
|
public static string ToastInstallSuccessBody(string version) => T(
|
||||||
|
$"PROSERVE v{version} est prête à être lancée.",
|
||||||
|
$"PROSERVE v{version} is ready to launch.",
|
||||||
|
$"PROSERVE v{version} 已就绪。",
|
||||||
|
$"PROSERVE v{version} พร้อมเปิดใช้งานแล้ว",
|
||||||
|
$"PROSERVE v{version} جاهز للتشغيل."
|
||||||
|
);
|
||||||
|
public static string ToastInstallErrorTitle(string version) => T(
|
||||||
|
$"Échec v{version}",
|
||||||
|
$"v{version} failed",
|
||||||
|
$"v{version} 失败",
|
||||||
|
$"v{version} ล้มเหลว",
|
||||||
|
$"v{version} فشل"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== RELEASE NOTES PLACEHOLDERS ====================
|
||||||
|
public static string ReleaseNotesNone => T("_Aucune release note fournie._", "_No release notes provided._", "_未提供版本说明。_", "_ไม่มีบันทึกการเปลี่ยนแปลง_", "_لا توجد ملاحظات إصدار._");
|
||||||
|
public static string ReleaseNotesUnavailable => T("_Release notes indisponibles._", "_Release notes unavailable._", "_版本说明不可用。_", "_บันทึกการเปลี่ยนแปลงไม่พร้อมใช้งาน_", "_ملاحظات الإصدار غير متاحة._");
|
||||||
|
|
||||||
|
// ==================== MISC ====================
|
||||||
|
public static string OpenButton => T("📁 Ouvrir", "📁 Open", "📁 打开", "📁 เปิด", "📁 فتح");
|
||||||
|
public static string CopyTooltip => T("Copier", "Copy", "复制", "คัดลอก", "نسخ");
|
||||||
|
public static string Minimize => T("Réduire", "Minimize", "最小化", "ย่อลง", "تصغير");
|
||||||
|
public static string Maximize => T("Agrandir", "Maximize", "最大化", "ขยาย", "تكبير");
|
||||||
|
public static string Restore => T("Restaurer", "Restore", "还原", "คืนค่า", "استعادة");
|
||||||
|
public static string CloseTooltip=> T("Fermer", "Close", "关闭", "ปิด", "إغلاق");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unités de taille fichier localisées (octet, kilo-octet, méga-octet, giga-octet, téra-octet).
|
||||||
|
/// FR : o/Ko/Mo/Go/To • EN : B/KB/MB/GB/TB • ZH : 字节/KB/MB/GB/TB • TH : ไบต์/KB/MB/GB/TB • AR : ب/ك.ب/م.ب/ج.ب/ت.ب
|
||||||
|
/// </summary>
|
||||||
|
private static string[] SizeUnits => _lang switch
|
||||||
|
{
|
||||||
|
"en" => new[] { "B", "KB", "MB", "GB", "TB" },
|
||||||
|
"zh" => new[] { "字节", "KB", "MB", "GB", "TB" },
|
||||||
|
"th" => new[] { "ไบต์", "KB", "MB", "GB", "TB" },
|
||||||
|
"ar" => new[] { "ب", "ك.ب", "م.ب", "ج.ب", "ت.ب" },
|
||||||
|
_ => new[] { "o", "Ko", "Mo", "Go", "To" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Format date court (ex. 29/04/2026 en FR, 4/29/2026 en US, 2026/4/29 en ZH).
|
||||||
|
/// Utilise la culture courante (réglée par Init()).
|
||||||
|
/// </summary>
|
||||||
|
public static string FormatDate(DateTime dt) =>
|
||||||
|
dt.ToLocalTime().ToString("d", CultureInfo.GetCultureInfo(_lang));
|
||||||
|
|
||||||
|
/// <summary>Format date court — overload sur Nullable<DateTime> (renvoie « — » si null).</summary>
|
||||||
|
public static string FormatDate(DateTime? dt) => dt is { } d ? FormatDate(d) : "—";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Format date long (jour de la semaine + jour + mois en lettres + année).
|
||||||
|
/// Ex. « lundi 29 avril 2026 » en FR, « Monday, April 29, 2026 » en EN.
|
||||||
|
/// </summary>
|
||||||
|
public static string FormatLongDate(DateTime dt) =>
|
||||||
|
dt.ToLocalTime().ToString("D", CultureInfo.GetCultureInfo(_lang));
|
||||||
|
|
||||||
|
/// <summary>Formatage canonique d'une taille en octets dans la langue active.</summary>
|
||||||
|
public static string FormatSize(long bytes)
|
||||||
|
{
|
||||||
|
if (bytes <= 0) return $"0 {SizeUnits[0]}";
|
||||||
|
var units = SizeUnits;
|
||||||
|
double v = bytes; int u = 0;
|
||||||
|
while (v >= 1024 && u < units.Length - 1) { v /= 1024; u++; }
|
||||||
|
return $"{v:0.#} {units[u]}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SizeLabel(string size) => T(
|
||||||
|
$"Taille : {size}", $"Size: {size}", $"大小:{size}", $"ขนาด: {size}", $"الحجم: {size}"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string SizeUnknown => T("taille inconnue", "unknown size", "未知大小", "ขนาดไม่ทราบ", "حجم غير معروف");
|
||||||
|
|
||||||
|
public static string UpdateAvailableHeading(string version) => T(
|
||||||
|
$"PROSERVE v{version} disponible",
|
||||||
|
$"PROSERVE v{version} available",
|
||||||
|
$"PROSERVE v{version} 可用",
|
||||||
|
$"PROSERVE v{version} พร้อมใช้งาน",
|
||||||
|
$"PROSERVE v{version} متاح"
|
||||||
|
);
|
||||||
|
|
||||||
|
public static string UpdateAvailableSubtitle(string date, string size) => T(
|
||||||
|
$"Date de release : {date} • {size}",
|
||||||
|
$"Release date: {date} • {size}",
|
||||||
|
$"发布日期:{date} • {size}",
|
||||||
|
$"วันเผยแพร่: {date} • {size}",
|
||||||
|
$"تاريخ الإصدار: {date} • {size}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== COPYRIGHT ====================
|
||||||
|
public static string Copyright => T(
|
||||||
|
"© 2026 ASTERION VR — Tous droits réservés",
|
||||||
|
"© 2026 ASTERION VR — All rights reserved",
|
||||||
|
"© 2026 ASTERION VR — 保留所有权利",
|
||||||
|
"© 2026 ASTERION VR — สงวนลิขสิทธิ์",
|
||||||
|
"© 2026 ASTERION VR — جميع الحقوق محفوظة"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user