v1.0.0 🎉 — Production release. i18n Espagnol + Allemand (launcher + emails).
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 <html> + <table>). 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) <noreply@anthropic.com>
This commit is contained in:
@@ -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.
|
||||
</p>
|
||||
<?php
|
||||
// Affichage en mode "1 par ligne" pour la lisibilité, peu importe
|
||||
// comment c'est stocké en DB (CSV).
|
||||
$currentEmails = Mailer::parseEmails($l['contact_emails'] ?? '');
|
||||
$currentDisplay = implode("\n", $currentEmails);
|
||||
$currentLang = trim((string)($l['language'] ?? ''));
|
||||
$langOptions = [
|
||||
'' => 'English (defaut)',
|
||||
'fr' => 'Français',
|
||||
'en' => 'English',
|
||||
'es' => 'Español',
|
||||
'de' => 'Deutsch',
|
||||
'zh' => '中文 (Chinese)',
|
||||
'th' => 'ภาษาไทย (Thai)',
|
||||
'ar' => 'العربية (Arabic)',
|
||||
];
|
||||
?>
|
||||
<form method="post">
|
||||
<?= Layout::csrfField() ?>
|
||||
<input type="hidden" name="action" value="set_contact_emails">
|
||||
<input type="hidden" name="id" value="<?= $l['id'] ?>">
|
||||
<div class="field">
|
||||
<label>Langue de l'email</label>
|
||||
<select name="language">
|
||||
<?php foreach ($langOptions as $code => $label):
|
||||
$sel = ($currentLang === $code) ? 'selected' : '';
|
||||
?>
|
||||
<option value="<?= htmlspecialchars($code) ?>" <?= $sel ?>><?= htmlspecialchars($label) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="hint" style="margin: 4px 0 0;">
|
||||
Langue dans laquelle l'email de notification sera rédigé.
|
||||
Le contenu des release notes reste toujours en anglais.
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Adresses email <span class="muted" style="font-weight: normal;">(<?= count($currentEmails) ?> actuellement)</span></label>
|
||||
<textarea name="contact_emails" rows="6"
|
||||
|
||||
Reference in New Issue
Block a user