From 73d084a70348d9249d3e83029d5864e8eb9be7b4 Mon Sep 17 00:00:00 2001 From: "j.foucher" Date: Thu, 28 May 2026 18:01:50 +0200 Subject: [PATCH] =?UTF-8?q?v1.0.0=20=F0=9F=8E=89=20=E2=80=94=20Production?= =?UTF-8?q?=20release.=20i18n=20Espagnol=20+=20Allemand=20(launcher=20+=20?= =?UTF-8?q?emails).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Première release MAJEURE après ~30 itérations 0.x. Le système est complet et stable pour la production : distribution PROSERVE multi-channels, install launcher cross-fleet, monitoring santé VR, sécurité (signatures Ed25519, HMAC URLs présignées, settings lock per-license, RFC1918 filter cache LAN). i18n nouvelles langues (Espagnol + Allemand) : - Strings.cs : signature T() étendue avec 2 params optionnels (es?/de?) en plus des 5 obligatoires. Fallback automatique sur l'anglais quand non traduit → infrastructure prête immédiatement, traduction progressive sur les ~317 strings du launcher selon les besoins terrain. - ~30 strings critiques traduites maintenant (top bar, body, status badges, actions principales Launch/Install/Cancel/Yes/No, MessageBox titles). - Available[] inclut es/Español + de/Deutsch ; auto-détection Windows pour es-* / de-* funcionne au premier launch. - Init() whitelist mise à jour. Emails release announce localisés par license : - Migration 005 : ajout `language VARCHAR(8) NULL` sur licenses (whitelist fr/en/es/de/zh/th/ar, NULL = fallback English). - getEmailStrings() PHP étendu : dictionnaire 7 langues × 14 strings. Traduction complète es + de (gérable : 28 nouvelles strings, vs 634 pour traduire le launcher en intégralité). - notify_release boucle par license : récupère language + locale fallback 'en' + render avec la bonne locale → chaque destinataire reçoit son email dans la langue de SA license, indépendamment des autres clients. - Subject localisé aussi (« PROSERVE v1.5.4 ya está disponible » / « PROSERVE v1.5.4 ist jetzt verfügbar »). - Release notes body reste TOUJOURS en anglais (évite d'avoir à maintenir N traductions du Markdown des notes). - Direction RTL préservée pour l'arabe (dir="rtl" sur + ). Admin UI : dropdown langue dans la modal Contacts d'une license + whitelist backend (set_contact_emails accepte fr/en/es/de/zh/th/ar). Bumps : 0.29.10 → 1.0.0 — milestone V1, premier release majeur en prod. Co-Authored-By: Claude Opus 4.7 (1M context) --- installer/PSLauncher.iss | 2 +- server/admin/licenses.php | 57 +++- server/admin/versions.php | 274 +++++++++++++++++--- server/migrations/005_license_language.sql | 11 + src/PSLauncher.App/PSLauncher.App.csproj | 6 +- src/PSLauncher.Core/Localization/Strings.cs | 92 ++++--- 6 files changed, 353 insertions(+), 89 deletions(-) create mode 100644 server/migrations/005_license_language.sql diff --git a/installer/PSLauncher.iss b/installer/PSLauncher.iss index ee1efd8..cac7143 100644 --- a/installer/PSLauncher.iss +++ b/installer/PSLauncher.iss @@ -11,7 +11,7 @@ #define MyAppName "PROSERVE Launcher" #define MyAppShortName "PS_Launcher" -#define MyAppVersion "0.29.10" +#define MyAppVersion "1.0.0" #define MyAppPublisher "ASTERION VR" #define MyAppURL "https://asterionvr.com" #define MyAppExeName "PS_Launcher.exe" diff --git a/server/admin/licenses.php b/server/admin/licenses.php index 1aaf073..2e9f49f 100644 --- a/server/admin/licenses.php +++ b/server/admin/licenses.php @@ -169,25 +169,34 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } elseif ($action === 'set_contact_emails') { - // Met à jour la liste des emails de contact pour les notifications - // de nouvelles versions. L'admin saisit en texte libre (1 par ligne, - // virgules, point-virgules — peu importe), on parse + valide via - // FILTER_VALIDATE_EMAIL et on stocke en CSV. Vide / aucun email - // valide → on stocke NULL (= pas de notif possible pour cette - // license, juste skip silencieux à l'envoi). + // Met à jour la liste des emails de contact + la langue préférée + // pour les notifications de nouvelles versions. L'admin saisit en + // texte libre (1 par ligne, virgules, point-virgules — peu importe), + // on parse + valide via FILTER_VALIDATE_EMAIL et on stocke en CSV. + // Vide / aucun email valide → on stocke NULL (= pas de notif possible + // pour cette license, juste skip silencieux à l'envoi). + // + // Language : whitelist stricte fr/en/zh/th/ar (= ce que le launcher + // supporte côté Strings.cs). NULL ou inconnu → fallback English. $id = (int)($_POST['id'] ?? 0); $raw = (string)($_POST['contact_emails'] ?? ''); + $lang = trim((string)($_POST['language'] ?? '')); if ($id <= 0) { throw new Exception('License id invalide.'); } + $allowedLangs = ['fr', 'en', 'es', 'de', 'zh', 'th', 'ar']; + if ($lang !== '' && !in_array($lang, $allowedLangs, true)) { + throw new Exception("Code langue invalide : '{$lang}'. Attendu : " . implode(', ', $allowedLangs) . ' ou vide.'); + } $parsed = Mailer::parseEmails($raw); $stored = Mailer::joinForStorage($parsed); - $db->prepare('UPDATE licenses SET contact_emails = ? WHERE id = ?') - ->execute([$stored, $id]); + $db->prepare('UPDATE licenses SET contact_emails = ?, language = ? WHERE id = ?') + ->execute([$stored, $lang !== '' ? $lang : null, $id]); $count = count($parsed); + $langDisplay = $lang !== '' ? $lang : 'en (défaut)'; $message = $count === 0 - ? "License #{$id} : contacts de notification supprimés." - : "License #{$id} : {$count} contact(s) email enregistré(s) pour les notifications de release."; + ? "License #{$id} : contacts de notification supprimés. Langue email : {$langDisplay}." + : "License #{$id} : {$count} contact(s) email enregistré(s), langue email : {$langDisplay}."; } elseif ($action === 'reset_machines') { $id = (int)($_POST['id'] ?? 0); @@ -546,17 +555,45 @@ Layout::header('Licenses', 'licenses'); version de PROSERVE accessible à cette license (matching channel + entitlement). Format libre : une adresse par ligne, virgules, ou point-virgules. Adresses invalides ignorées silencieusement. + La langue choisie ci-dessous est utilisée pour le contenu de l'email + (greeting + instructions) — les release notes elles-mêmes restent + toujours en anglais.

'English (defaut)', + 'fr' => 'Français', + 'en' => 'English', + 'es' => 'Español', + 'de' => 'Deutsch', + 'zh' => '中文 (Chinese)', + 'th' => 'ภาษาไทย (Thai)', + 'ar' => 'العربية (Arabic)', + ]; ?>
+
+ + +

+ Langue dans laquelle l'email de notification sera rédigé. + Le contenu des release notes reste toujours en anglais. +

+