etm-powersync-app/lib/l10n/app_localizations.dart
Patrick Schurig 553a182e9b fix(config): l'ordre entrelacé se voit enfin, et un appareil disparu cesse d'être un défaut à lever
L'arrivée de la V2C sur .75 a révélé deux défauts que le banc ne pouvait pas montrer avant,
plus deux pièges de contrat à documenter.

1. ⚠️ isNotGrouped ÉTAIT CALCULÉ ET AFFICHÉ NULLE PART. GroupedOrder détecte depuis le
   premier jour qu'un ordre n'est pas groupé par domaine, le provider l'expose, et aucune
   vue ne le lisait — le cas ne s'était jamais produit, chaque domaine du banc ayant ses
   charges d'un seul tenant.

   Il se produit maintenant : la V2C, créée d'office au rang 1 que le chauffe-eau occupait
   déjà, donne l'ordre à plat « ecs · ev · heating · ev · ev ». Le domaine ev est coupé en
   deux par le chauffage.

   Ce n'était pas un détail d'affichage. L'écran groupe pour afficher, donc ce qu'on voit
   n'est plus l'ordre réel de la box — et le premier enregistrement réaplatit EN GROUPANT,
   ce qui change l'arbitrage sans que personne ne l'ait demandé. Chiffré par test sur la
   configuration réelle : la PAC passerait du rang 2 au rang 5. C'est exactement ce que le
   commentaire de GroupedOrder interdit depuis le début ; le garde-fou existait, il n'était
   pas branché.

2. « L'APPAREIL N'EXISTE PLUS » N'EST PAS UN DÉFAUT À LEVER. La Terra AC a été supprimée de
   nymea ; son entrée LoadConfig survit, occupe le rang 4, et s'affiche en THING_MISSING
   avec un bouton « Lever le défaut ». ClearLoadFault y répondrait EnergyErrorNoError sans
   rien changer, et le défaut reviendrait au cycle suivant — un bouton qui ne peut pas
   tenir sa promesse fait douter de la box au lieu de désigner la cause.

   Le bouton disparaît sur ce code, remplacé par ce qu'il faut faire : réinstaller
   l'appareil, ou retirer la charge. Et le libellé cesse de se lire « votre configuration
   est cassée » : le cas normal est un appareil remplacé, le plugin crée d'office une
   entrée par borne détectée mais ne la retire pas quand le Thing s'en va.

3. Deux pièges du Thing V2C, documentés là où quelqu'un serait tenté de les câbler :

   chargeEnergy est EXACT pendant la charge — sa croissance recoupe currentPower à mieux
   d'un pour cent — et REMIS À ZÉRO à l'arrêt de la charge, pas au débranchement. Mesuré :
   0,3456 kWh → 0 dès que charging passe à faux, 119 secondes avant que le câble ne bouge.
   Sur du pilotage par surplus il repartirait de zéro à chaque nuage, et après coup une
   nuit entière vaudrait 0 — soit « rien livré » affiché là où la vérité est « pas
   mesurable ». Le plugin publiera un sessionEnergy construit ; rien n'est bâti en
   attendant, et surtout aucune accumulation côté app.

   powerL1/L2/L3 sont des ampères mal nommés, renommage currentL* en cours côté plugin.
   Ni affichage, ni conversion : une conversion écrite ici survivrait au correctif et le
   contredirait.

Fixture ajoutée : la configuration réelle à cinq entrées, avec ses deux enseignements de
terrain — deux rangs à 1, et une entrée orpheline qui consomme un rang.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
2026-08-28 11:57:12 +02:00

821 lines
30 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_fr.dart';
// ignore_for_file: type=lint
/// Callers can lookup localized strings with an instance of L10n
/// returned by `L10n.of(context)`.
///
/// Applications need to include `L10n.delegate()` in their app's
/// `localizationDelegates` list, and the locales they support in the app's
/// `supportedLocales` list. For example:
///
/// ```dart
/// import 'l10n/app_localizations.dart';
///
/// return MaterialApp(
/// localizationsDelegates: L10n.localizationsDelegates,
/// supportedLocales: L10n.supportedLocales,
/// home: MyApplicationHome(),
/// );
/// ```
///
/// ## Update pubspec.yaml
///
/// Please make sure to update your pubspec.yaml to include the following
/// packages:
///
/// ```yaml
/// dependencies:
/// # Internationalization support.
/// flutter_localizations:
/// sdk: flutter
/// intl: any # Use the pinned version from flutter_localizations
///
/// # Rest of dependencies
/// ```
///
/// ## iOS Applications
///
/// iOS applications define key application metadata, including supported
/// locales, in an Info.plist file that is built into the application bundle.
/// To configure the locales supported by your app, you’ll need to edit this
/// file.
///
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// project’s Runner folder.
///
/// Next, select the Information Property List item, select Add Item from the
/// Editor menu, then select Localizations from the pop-up menu.
///
/// Select and expand the newly-created Localizations item then, for each
/// locale your application supports, add a new item and select the locale
/// you wish to add from the pop-up menu in the Value field. This list should
/// be consistent with the languages listed in the L10n.supportedLocales
/// property.
abstract class L10n {
L10n(String locale)
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static L10n? of(BuildContext context) {
return Localizations.of<L10n>(context, L10n);
}
static const LocalizationsDelegate<L10n> delegate = _L10nDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
<LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[Locale('fr')];
/// Titre de l'écran installateur de configuration des charges pilotables
///
/// In fr, this message translates to:
/// **'Rôles & appareils'**
String get installerLoadsTitle;
/// No description provided for @installerLoadsSubtitle.
///
/// In fr, this message translates to:
/// **'Ordre de service des charges pilotables'**
String get installerLoadsSubtitle;
/// No description provided for @loadsEmpty.
///
/// In fr, this message translates to:
/// **'Aucune charge pilotable déclarée sur cette installation.'**
String get loadsEmpty;
/// No description provided for @loadsLoadError.
///
/// In fr, this message translates to:
/// **'Lecture de la configuration impossible : {error}'**
String loadsLoadError(String error);
/// Bucket des charges sans o:domain — jamais rangées d'office dans un domaine
///
/// In fr, this message translates to:
/// **'Non classé'**
String get sectionUnclassified;
/// No description provided for @domainEv.
///
/// In fr, this message translates to:
/// **'Véhicule électrique'**
String get domainEv;
/// No description provided for @domainEcs.
///
/// In fr, this message translates to:
/// **'Eau chaude sanitaire'**
String get domainEcs;
/// No description provided for @domainHvac.
///
/// In fr, this message translates to:
/// **'Climatisation'**
String get domainHvac;
/// No description provided for @domainHeating.
///
/// In fr, this message translates to:
/// **'Chauffage'**
String get domainHeating;
/// Repli quand la box renvoie un domaine que cette version d'app ne connaît pas
///
/// In fr, this message translates to:
/// **'Domaine « {code} »'**
String domainUnknown(String code);
/// No description provided for @adapterRelayRouter.
///
/// In fr, this message translates to:
/// **'Routeur de relais'**
String get adapterRelayRouter;
/// No description provided for @adapterEtmVariableLoad.
///
/// In fr, this message translates to:
/// **'Charge modulable'**
String get adapterEtmVariableLoad;
/// No description provided for @adapterSgReady.
///
/// In fr, this message translates to:
/// **'SG-Ready'**
String get adapterSgReady;
/// No description provided for @adapterEvCharger.
///
/// In fr, this message translates to:
/// **'Borne de recharge'**
String get adapterEvCharger;
/// No description provided for @adapterUnknown.
///
/// In fr, this message translates to:
/// **'Mécanisme « {code} »'**
String adapterUnknown(String code);
/// No description provided for @loadEnabled.
///
/// In fr, this message translates to:
/// **'Active'**
String get loadEnabled;
/// No description provided for @loadDisabled.
///
/// In fr, this message translates to:
/// **'Exclue de l\'arbitrage'**
String get loadDisabled;
/// No description provided for @loadPriority.
///
/// In fr, this message translates to:
/// **'Rang {rank}'**
String loadPriority(int rank);
/// No description provided for @loadMinOn.
///
/// In fr, this message translates to:
/// **'Maintien ON minimal : {seconds} s'**
String loadMinOn(int seconds);
/// No description provided for @loadMinOff.
///
/// In fr, this message translates to:
/// **'Maintien OFF minimal : {seconds} s'**
String loadMinOff(int seconds);
/// No description provided for @loadRelayCount.
///
/// In fr, this message translates to:
/// **'{count, plural, =1{1 relais} other{{count} relais}}'**
String loadRelayCount(int count);
/// Emplacement visuel réservé — LoadConfig n'a aucun champ pour rattacher un compteur à une charge
///
/// In fr, this message translates to:
/// **'Compteur dédié : non rattachable'**
String get loadMeterSlot;
/// No description provided for @orderNotGroupedTitle.
///
/// In fr, this message translates to:
/// **'Ordre non groupé'**
String get orderNotGroupedTitle;
/// No description provided for @orderNotGroupedBody.
///
/// In fr, this message translates to:
/// **'L\'ordre en place sur la box n\'est pas groupé par domaine : les charges d\'un même domaine ne se suivent pas. L\'ordre réel est affiché ci-dessous, tel que la box l\'applique.'**
String get orderNotGroupedBody;
/// No description provided for @orderNotGroupedAction.
///
/// In fr, this message translates to:
/// **'Normaliser l\'ordre'**
String get orderNotGroupedAction;
/// No description provided for @orderNotGroupedWarning.
///
/// In fr, this message translates to:
/// **'Normaliser modifiera l\'ordre d\'arbitrage réel de l\'installation. Aucune écriture ne part tant que vous n\'avez pas confirmé.'**
String get orderNotGroupedWarning;
/// No description provided for @orderNormalizeConfirm.
///
/// In fr, this message translates to:
/// **'Normaliser et enregistrer'**
String get orderNormalizeConfirm;
/// No description provided for @cancel.
///
/// In fr, this message translates to:
/// **'Annuler'**
String get cancel;
/// No description provided for @saveOrder.
///
/// In fr, this message translates to:
/// **'Enregistrer l\'ordre'**
String get saveOrder;
/// No description provided for @savePending.
///
/// In fr, this message translates to:
/// **'Envoi en cours…'**
String get savePending;
/// No description provided for @saveWaitingBox.
///
/// In fr, this message translates to:
/// **'En attente de confirmation de la box…'**
String get saveWaitingBox;
/// No description provided for @saveConfirmed.
///
/// In fr, this message translates to:
/// **'Configuration confirmée par la box.'**
String get saveConfirmed;
/// No description provided for @saveRejected.
///
/// In fr, this message translates to:
/// **'La box a refusé : {reason}'**
String saveRejected(String reason);
/// No description provided for @saveDiverged.
///
/// In fr, this message translates to:
/// **'La box a enregistré un état différent de celui demandé. L\'affichage montre ce que la box applique réellement.'**
String get saveDiverged;
/// No description provided for @validationDuplicateId.
///
/// In fr, this message translates to:
/// **'L\'identifiant de charge « {id} » apparaît deux fois.'**
String validationDuplicateId(String id);
/// No description provided for @validationThingClaimedTwice.
///
/// In fr, this message translates to:
/// **'L\'appareil {thingId} est commandé par deux charges actives, « {first} » et « {second} » : deux commandes contradictoires et une puissance comptée deux fois.'**
String validationThingClaimedTwice(
String thingId,
String first,
String second,
);
/// No description provided for @telemetryUnavailableTitle.
///
/// In fr, this message translates to:
/// **'Télémétrie indisponible'**
String get telemetryUnavailableTitle;
/// No description provided for @telemetryUnavailableBody.
///
/// In fr, this message translates to:
/// **'Cette box n\'expose pas GetLoadTelemetry. Puissance allouée, verrous, disponibilité et motifs de décision ne sont pas lisibles depuis l\'app.'**
String get telemetryUnavailableBody;
/// No description provided for @telemetryStale.
///
/// In fr, this message translates to:
/// **'Données anciennes — dernier point il y a {seconds} s'**
String telemetryStale(int seconds);
/// No description provided for @telemetryDegradedMode.
///
/// In fr, this message translates to:
/// **'Mode dégradé L2 — compteur muet, planification suspendue'**
String get telemetryDegradedMode;
/// No description provided for @faultTitle.
///
/// In fr, this message translates to:
/// **'En défaut'**
String get faultTitle;
/// No description provided for @faultClearAction.
///
/// In fr, this message translates to:
/// **'Lever le défaut'**
String get faultClearAction;
/// No description provided for @faultCleared.
///
/// In fr, this message translates to:
/// **'Défaut levé — confirmé par la télémétrie relue.'**
String get faultCleared;
/// No description provided for @faultClearNoop.
///
/// In fr, this message translates to:
/// **'Aucun défaut à lever sur cette charge.'**
String get faultClearNoop;
/// No description provided for @faultUnknown.
///
/// In fr, this message translates to:
/// **'Défaut « {code} »'**
String faultUnknown(String code);
/// Repli obligatoire quand la box renvoie un decision.code absent de cet ARB — box plus récente que l'app. Affiche le code brut et ses paramètres, jamais une phrase vide.
///
/// In fr, this message translates to:
/// **'Décision « {code} »{params}'**
String decisionUnknown(String code, String params);
/// No description provided for @telemetryTitle.
///
/// In fr, this message translates to:
/// **'Arbitrage en direct'**
String get telemetryTitle;
/// timestamp absent — l'absence de cycle est une information, pas un zéro
///
/// In fr, this message translates to:
/// **'Aucun cycle d\'arbitrage depuis le démarrage du service.'**
String get telemetryNeverRan;
/// No description provided for @telemetryLastCycle.
///
/// In fr, this message translates to:
/// **'Dernier cycle il y a {seconds} s'**
String telemetryLastCycle(int seconds);
/// No description provided for @telemetryBudgetTitle.
///
/// In fr, this message translates to:
/// **'Budget de surplus du cycle'**
String get telemetryBudgetTitle;
/// No description provided for @telemetryBudgetAbsent.
///
/// In fr, this message translates to:
/// **'Aucun budget publié pour ce cycle : la planification est suspendue.'**
String get telemetryBudgetAbsent;
/// No description provided for @budgetSurplus.
///
/// In fr, this message translates to:
/// **'Surplus entrant'**
String get budgetSurplus;
/// No description provided for @budgetEvReserved.
///
/// In fr, this message translates to:
/// **'Réservé au véhicule'**
String get budgetEvReserved;
/// No description provided for @budgetRecredited.
///
/// In fr, this message translates to:
/// **'Recrédité'**
String get budgetRecredited;
/// No description provided for @budgetAllocated.
///
/// In fr, this message translates to:
/// **'Alloué'**
String get budgetAllocated;
/// No description provided for @budgetRemaining.
///
/// In fr, this message translates to:
/// **'Reliquat'**
String get budgetRemaining;
/// No description provided for @watts.
///
/// In fr, this message translates to:
/// **'{watts} W'**
String watts(int watts);
/// No description provided for @telemetryAllocated.
///
/// In fr, this message translates to:
/// **'Alloué {watts} W'**
String telemetryAllocated(int watts);
/// ÉTAT RÉEL, lu dans mechanism.chargingEnabled / currentA / phaseCount — qui viennent du Thing, pas de l'arbitre.
///
/// In fr, this message translates to:
/// **'Borne : en charge, {current} A sur {phases} phase(s)'**
String telemetryEvCharging(double current, int phases);
/// No description provided for @telemetryEvIdle.
///
/// In fr, this message translates to:
/// **'Borne : ne charge pas'**
String get telemetryEvIdle;
/// No description provided for @telemetryEvUnplugged.
///
/// In fr, this message translates to:
/// **'Borne : aucun véhicule branché'**
String get telemetryEvUnplugged;
/// mechanism.chargingEnabled absent. Ne rien dire vaut mieux que déduire l'état du motif d'arbitrage, qui peut le contredire.
///
/// In fr, this message translates to:
/// **'Borne : état non publié ce cycle'**
String get telemetryEvStateUnknown;
/// funding == « grid » : l'allocation vit dans budget.evReservedW, pas dans budget.allocatedW. Sans cette mention, l'utilisateur voit une charge servie alors que le surplus est nul et croit à un défaut.
///
/// In fr, this message translates to:
/// **'Financée au réseau (échéance ou tarif dynamique) — hors budget de surplus'**
String get telemetryFundedByGrid;
/// Charge présente dans GetLoadConfig mais absente de loads[] : elle est désactivée, jamais perdue
///
/// In fr, this message translates to:
/// **'Non arbitrée — absente du dernier cycle publié'**
String get telemetryNotArbitrated;
/// No description provided for @lockMinOn.
///
/// In fr, this message translates to:
/// **'Maintien ON — {seconds} s restantes'**
String lockMinOn(int seconds);
/// No description provided for @lockMinOff.
///
/// In fr, this message translates to:
/// **'Maintien OFF — {seconds} s restantes'**
String lockMinOff(int seconds);
/// No description provided for @lockMinStateHold.
///
/// In fr, this message translates to:
/// **'Maintien d\'état — {seconds} s restantes'**
String lockMinStateHold(int seconds);
/// No description provided for @lockUnknown.
///
/// In fr, this message translates to:
/// **'Verrou « {kind} » — {seconds} s restantes'**
String lockUnknown(String kind, int seconds);
/// Les secondes restantes ne sont PAS décomptées côté app : elles datent du cycle publié
///
/// In fr, this message translates to:
/// **'au dernier cycle'**
String get lockAsOfCycle;
/// No description provided for @mechanismRelayStage.
///
/// In fr, this message translates to:
/// **'Palier {stage} W sur {max} W'**
String mechanismRelayStage(int stage, int max);
/// No description provided for @mechanismVariableSetpoint.
///
/// In fr, this message translates to:
/// **'Consigne {setpoint} W ({percent} %)'**
String mechanismVariableSetpoint(int setpoint, int percent);
/// No description provided for @mechanismSgReadyState.
///
/// In fr, this message translates to:
/// **'État SG-Ready {state} — estimation {estimated} W'**
String mechanismSgReadyState(int state, int estimated);
/// No description provided for @mechanismEvCharger.
///
/// In fr, this message translates to:
/// **'{current} A sur {phases} phase(s)'**
String mechanismEvCharger(double current, int phases);
/// No description provided for @mechanismUnknown.
///
/// In fr, this message translates to:
/// **'Mécanisme « {kind} »'**
String mechanismUnknown(String kind);
/// No description provided for @decisionEvSurplus.
///
/// In fr, this message translates to:
/// **'Véhicule rechargé sur le surplus photovoltaïque.'**
String get decisionEvSurplus;
/// No description provided for @decisionEvSpotMarket.
///
/// In fr, this message translates to:
/// **'Véhicule rechargé sur un créneau tarifaire favorable.'**
String get decisionEvSpotMarket;
/// No description provided for @decisionEvDeadline.
///
/// In fr, this message translates to:
/// **'Véhicule prioritaire : l\'échéance approche.'**
String get decisionEvDeadline;
/// No description provided for @decisionEvEcoMin.
///
/// In fr, this message translates to:
/// **'Pas de surplus : le courant minimum est maintenu.'**
String get decisionEvEcoMin;
/// No description provided for @decisionEvIdle.
///
/// In fr, this message translates to:
/// **'Pas de surplus : la recharge est suspendue.'**
String get decisionEvIdle;
/// No description provided for @decisionLoadUnavailable.
///
/// In fr, this message translates to:
/// **'Charge en défaut : aucune commande n\'est émise, et {frozen} W restent comptés au budget.'**
String decisionLoadUnavailable(int frozen);
/// No description provided for @decisionLockMinOn.
///
/// In fr, this message translates to:
/// **'Le maintien ON a relevé la consigne à {applied} W ; le budget en payait {budget} W.'**
String decisionLockMinOn(int applied, int budget);
/// No description provided for @decisionLockMinOff.
///
/// In fr, this message translates to:
/// **'Le maintien OFF interdit l\'enclenchement ; le budget payait pourtant {requested} W sur {budget} W disponibles.'**
String decisionLockMinOff(int requested, int budget);
/// No description provided for @decisionLockMinOffCapped.
///
/// In fr, this message translates to:
/// **'Le maintien OFF plafonne la consigne à {applied} W ; {requested} W étaient demandés sur {budget} W de budget.'**
String decisionLockMinOffCapped(int applied, int requested, int budget);
/// No description provided for @decisionSurplusSetpoint.
///
/// In fr, this message translates to:
/// **'Consigne de {setpoint} W servie par le surplus ({budget} W de budget).'**
String decisionSurplusSetpoint(int setpoint, int budget);
/// No description provided for @decisionSurplusSetpointStepped.
///
/// In fr, this message translates to:
/// **'Consigne de {setpoint} W servie par le surplus, arrondie sur un palier déclaré ({budget} W de budget).'**
String decisionSurplusSetpointStepped(int setpoint, int budget);
/// No description provided for @decisionSurplusInsufficient.
///
/// In fr, this message translates to:
/// **'Aucun surplus à distribuer ({budget} W) — rien n\'est commandé.'**
String decisionSurplusInsufficient(int budget);
/// No description provided for @decisionLockMinStateHold.
///
/// In fr, this message translates to:
/// **'État {state} maintenu par protection anti court-cycle.'**
String decisionLockMinStateHold(int state);
/// No description provided for @decisionSgForced.
///
/// In fr, this message translates to:
/// **'Pompe à chaleur en état 4 (forcé) — estimation {estimated} W sur {budget} W de budget.'**
String decisionSgForced(int estimated, int budget);
/// No description provided for @decisionSgRecommended.
///
/// In fr, this message translates to:
/// **'Pompe à chaleur en état 3 (recommandation) — estimation {estimated} W sur {budget} W de budget.'**
String decisionSgRecommended(int estimated, int budget);
/// No description provided for @decisionSgNormal.
///
/// In fr, this message translates to:
/// **'Aucun surplus ({budget} W) — pompe à chaleur en état 2 (normal, sans consigne).'**
String decisionSgNormal(int budget);
/// Il Y A du surplus, mais pas au bon format : sous le plus petit palier commandable. À ne pas confondre avec SURPLUS_INSUFFICIENT, qui dit qu'il n'y a rien.
///
/// In fr, this message translates to:
/// **'Budget de {budget} W sous le premier palier ({min} W) — rien n\'est commandé, le budget passe à la charge suivante.'**
String decisionBelowMinPower(int budget, int min);
/// Même sens, mécanisme à états : le premier état utile coûterait plus que ce qui reste.
///
/// In fr, this message translates to:
/// **'Budget de {budget} W sous l\'état {state} ({min} W estimés) — maintien en état 2, le budget passe à la charge suivante.'**
String decisionBelowMinPowerState(int budget, int state, int min);
/// EV_GRID_START. La borne démarre alors que le surplus ne paie pas son plancher : acquisitionTolerance autorise l'appoint. gridW = floorW − budgetW est CE QUI EST ACHETÉ — c'est le chiffre qui fait de cette ligne une décision et non un effet de bord, donc il vient en tête. Motif préparé mais JAMAIS vu sur machine au 2026-08-27 : ne rien bâtir autour.
///
/// In fr, this message translates to:
/// **'Démarrage soutiré : {grid} W achetés au réseau pour compléter les {budget} W de surplus et atteindre le plancher de {floor} W.'**
String decisionEvGridStart(int grid, int budget, int floor);
/// PHASE_LIMIT. Deux causes, deux gestes : la limite de phase se règle en délestant la maison ou en revoyant l'abonnement, le manque de surplus s'attend. Confondre les deux envoie chercher du soleil là où il faut lire un compteur — d'où la seconde moitié de la phrase.
///
/// In fr, this message translates to:
/// **'Limite de phase atteinte : {limit} W disponibles pour {required} W exigés — ce n\'est pas le surplus qui manque.'**
String decisionPhaseLimit(int limit, int required);
/// Variante NOMINALE : le plugin publie toujours les trois paramètres ensemble, et sa garde interne exige withheldW > 0 — un motif à 0 W dirait « une règle vous bloque » là où il n'y a simplement pas de surplus. Le nombre de watts retenus vient en TÊTE parce que c'est lui qui rend la cause lisible : « 3 200 W retenus » se comprend, « batterie à 47 % » se subit.
///
/// In fr, this message translates to:
/// **'{withheld} W de surplus retenus par la réserve batterie ({soc} % sous le seuil de {seuil} %) — il y a du surplus, mais une règle interdit de le distribuer.'**
String decisionBatteryReserveWithheld(int withheld, int soc, int seuil);
/// Repli si « withheldW » manque (box plus ancienne). À NE PAS confondre avec « pas de surplus » : le surplus existe, une règle l'annule. Le client voit une installation qui ne pilote rien par grand soleil, sans erreur ni panne — la phrase doit donc nommer la cause, pas décrire l'effet.
///
/// In fr, this message translates to:
/// **'Budget annulé par la réserve batterie ({soc} % sous le seuil de {seuil} %) — il y a du surplus, mais une règle interdit de le distribuer.'**
String decisionBatteryReserve(int soc, int seuil);
/// Variante sans paramètres, si le motif n'en porte pas.
///
/// In fr, this message translates to:
/// **'Budget annulé par la réserve batterie — il y a du surplus, mais une règle interdit de le distribuer.'**
String get decisionBatteryReserveShort;
/// No description provided for @decisionDegradedL2.
///
/// In fr, this message translates to:
/// **'Consigne de repli : le compteur est muet et le watchdog a suspendu la planification.'**
String get decisionDegradedL2;
/// No description provided for @decisionSafeStateRelay.
///
/// In fr, this message translates to:
/// **'État sûr avant retrait : tous les relais sont ouverts.'**
String get decisionSafeStateRelay;
/// No description provided for @decisionSafeStateSetpoint.
///
/// In fr, this message translates to:
/// **'État sûr avant retrait : consigne ramenée à 0 W.'**
String get decisionSafeStateSetpoint;
/// No description provided for @decisionSafeStateSgReady.
///
/// In fr, this message translates to:
/// **'État sûr avant retrait : état 2 (normal), jamais le blocage.'**
String get decisionSafeStateSgReady;
/// No description provided for @faultWriteFailed.
///
/// In fr, this message translates to:
/// **'Échec d\'écriture : l\'échelle de commande est épuisée, plus aucune commande n\'est émise tant que le défaut n\'est pas levé.'**
String get faultWriteFailed;
/// À NE PAS lire comme « votre configuration est cassée ». Le cas normal est un appareil physiquement remplacé : le Thing disparaît, l'entrée LoadConfig reste — le plugin crée d'office une entrée par borne détectée mais ne la retire pas quand le Thing s'en va. Constaté sur .75 le 2026-08-28 avec une ABB Terra AC remplacée par une V2C.
///
/// In fr, this message translates to:
/// **'L\'appareil commandé n\'existe plus dans nymea — retiré, ou jamais réinstallé après un remplacement. La charge, elle, est toujours déclarée : c\'est pour ça qu\'elle apparaît ici.'**
String get faultThingMissing;
/// Remplace le bouton « Lever le défaut » sur THING_MISSING. ClearLoadFault y répondrait EnergyErrorNoError sans rien changer, et le défaut reviendrait au cycle suivant — un bouton qui ne peut pas tenir sa promesse est pire que pas de bouton.
///
/// In fr, this message translates to:
/// **'Rien à lever ici : le défaut ne partira pas tant qu\'aucun appareil ne répond. Réinstallez-le dans nymea, ou retirez cette charge de la configuration.'**
String get faultThingMissingAction;
/// No description provided for @faultUnusableEncoding.
///
/// In fr, this message translates to:
/// **'Encodage SG-Ready inexploitable : l\'état 2 ne peut pas être exprimé, cette pompe à chaleur n\'est pas pilotable.'**
String get faultUnusableEncoding;
/// No description provided for @faultClearPending.
///
/// In fr, this message translates to:
/// **'Levée demandée — en attente de la télémétrie…'**
String get faultClearPending;
/// No description provided for @faultClearStillFaulty.
///
/// In fr, this message translates to:
/// **'La charge est toujours en défaut après la levée.'**
String get faultClearStillFaulty;
/// No description provided for @faultClearRejected.
///
/// In fr, this message translates to:
/// **'La box a refusé la levée : {reason}'**
String faultClearRejected(String reason);
/// No description provided for @faultClearHint.
///
/// In fr, this message translates to:
/// **'La levée est une action délibérée : le défaut ne se lève jamais tout seul.'**
String get faultClearHint;
/// No description provided for @domainBattery.
///
/// In fr, this message translates to:
/// **'Batterie'**
String get domainBattery;
/// No description provided for @domainAssignTitle.
///
/// In fr, this message translates to:
/// **'Classer « {label} »'**
String domainAssignTitle(String label);
/// No description provided for @domainAssignAction.
///
/// In fr, this message translates to:
/// **'Changer de domaine'**
String get domainAssignAction;
/// No description provided for @domainAssignNone.
///
/// In fr, this message translates to:
/// **'Retirer du classement'**
String get domainAssignNone;
/// No description provided for @domainAssignHint.
///
/// In fr, this message translates to:
/// **'Le domaine est une intention déclarée par l\'installateur. L\'arbitre ne la lit pas : elle ne sert qu\'à grouper l\'ordre de service.'**
String get domainAssignHint;
/// No description provided for @localeRequested.
///
/// In fr, this message translates to:
/// **'Locale demandée : {requested} · retenue par la box : {effective}'**
String localeRequested(String requested, String effective);
}
class _L10nDelegate extends LocalizationsDelegate<L10n> {
const _L10nDelegate();
@override
Future<L10n> load(Locale locale) {
return SynchronousFuture<L10n>(lookupL10n(locale));
}
@override
bool isSupported(Locale locale) =>
<String>['fr'].contains(locale.languageCode);
@override
bool shouldReload(_L10nDelegate old) => false;
}
L10n lookupL10n(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'fr':
return L10nFr();
}
throw FlutterError(
'L10n.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.',
);
}