// ───────────────────────────────────────────────────────────── // libreDecision v2 — lexicon: SINGLE source of French UI labels. // Tone rules (BLUEPRINT-V2.md): // 1. tutoyer la personne dans ses gestes ; // 2. actes collectifs à l'infinitif (« Adopter notre Pacte ») ; // 3. sujet grammatical des phrases générées = les personnes ou le collectif, // JAMAIS la formule ou le système. // The anti-lexicon vitest test (tests/lexicon.spec.ts) enforces FORBIDDEN_UI_TERMS // over every UI-visible string (lexicon + .vue templates). // ───────────────────────────────────────────────────────────── import type { DecisionRoute, DecisionStatus, InertiaPreset, NominationMethod, NuancedValue, VoteMethod, Weight, Reversibility, } from '~/types/domain' /** Words that must NEVER appear in UI-visible text (case-insensitive, accent-aware). * They may exist as code identifiers — the test only scans UI strings. */ export const FORBIDDEN_UI_TERMS = [ 'déléguer', 'délégation', 'délégué', 'dette', 'retard', 'en souffrance', 'corpus', 'snapshot', 'verdict', 'triage', 'oligarchie', 'peuple adulte', ] as const // ── Routes — first person: the path is a gesture, not a category ── export const ROUTE_LABELS: Record = { solo: 'Je décide', mandate: 'Je décide, sous mandat', transmit: 'Je transmets', advice: "J'écoute, puis je décide", collective: 'Nous décidons', record: 'Je le consigne', } /** Short pill forms (registry filters). */ export const ROUTE_SHORT: Record = { solo: 'seul', mandate: 'sous mandat', transmit: 'transmis', advice: 'sur avis', collective: 'ensemble', record: 'consigné', } export const ROUTE_ICONS: Record = { solo: 'i-lucide-zap', mandate: 'i-lucide-key-round', transmit: 'i-lucide-send', advice: 'i-lucide-message-circle', collective: 'i-lucide-users', record: 'i-lucide-notebook-pen', } export const ICONS = { urgent: 'i-lucide-siren', alreadyDecided: 'i-lucide-book-open-check', recurrence: 'i-lucide-repeat', parametric: 'i-lucide-sliders-horizontal', crystallize: 'i-lucide-stamp', } as const // ── Decision states — plain French pills ── export const STATUS_LABELS: Record = { draft: 'préparation', advice: 'avis', objection: 'objection', framing: 'formulation', voting: 'vote', adopted: 'en vigueur', rejected: 'rejeté', revoked: 'révoqué', transmitted: 'transmis', closed: 'clos', } /** Session display state (frozen lives on VoteSession, shown as a decision badge). */ export const FROZEN_LABEL = 'figé' export const FROZEN_BANNER = 'Votes figés — en attente de cristallisation' // ── Weight & reversibility — the tunnel chips ── export const WEIGHT_LABELS: Record = { light: 'rien de lourd', binding: 'du temps ou des ressources', structural: 'la structure, les règles, du long terme', } export const REVERSIBILITY_LABELS: Record = { easy: 'facilement réversible', costly: 'coûteux à défaire', irreversible: 'irréversible', } // ── Nuanced scale — never « CONTRE » ── export const NUANCED_LABELS: Record = { 0: 'Pas du tout', 1: 'Plutôt non', 2: 'Réservé', 3: 'Plutôt oui', 4: 'Oui', 5: 'Tout à fait', } // ── Vote methods ── export const METHOD_LABELS: Record = { consent: 'Consentement', binary: 'Pour / contre', nuanced: 'Vote nuancé', parametric: 'Réglage collectif', election: 'Élection', } export const BINARY_COST = 'deux camps, un perdant' export const BINARY_DESCRIPTION = "l'outil de dernier recours des très grands corps" // ── The review — l'épreuve du réel ── export const REVIEW_TITLE = "L'épreuve du réel" export const REVIEW_QUESTION = 'Le réel a-t-il suivi ?' export const REVIEW_VERDICTS = { confirmed: 'Ça tient', revise: 'À revoir', revoke: 'À révoquer', } as const // ── Windows, assent, perimeter ── export const WINDOW_OK = 'Ça me va' export const WINDOW_OBJECT = "J'objecte" export const ASSENT_MISSING = 'Il manque un accord explicite' export const BOUNDARY_SUSPENDED = 'compte à rebours suspendu — frontière contestée' export const CONCERN_FIRST = 'Concerné·e en premier lieu' export const CONCERN_SECOND = "Concerné·e en second lieu — s'est déclaré·e" export const CONCERN_ME = 'Ça me concerne' export const PERIMETER_OVERFLOW = "Le périmètre déborde — élargis d'un cran" export const SCOPE_WIDEN = "Élargir d'un cran" export const SCOPE_KEEP = 'Maintenir — en motivant publiquement' // ── Parametric — le réglage collectif ── export const PARAMETRIC_ALT = 'C\'est un réglage (montant, taux, répartition) — décidez au curseur' export const PARAM_CONSTRAINT_LABEL = 'contrainte' export const PARAM_DERIVED_LABEL = 'calculé' export const IMPACT_CARD_TITLE = 'Pour moi' export const IMPACT_DISCLAIMER = 'estimation sur données déclarées' export const EXPLORE_LABEL = 'Explorer' export const EXPLORE_DISCLAIMER = 'exploration — ne compte pas' export const CRYSTALLIZE_ACTION = 'Cristalliser' export const CRYSTALLIZE_CARD = 'Les votes sont figés — cristallise la médiane' export const MEDIAN_EXPLANATION = 'Le collectif retient la médiane de chaque curseur — robuste aux extrêmes, ' + "et c'est une position que chacun aurait pu proposer." export const BIMODAL_BANNER = (paramLabel: string) => `Deux positions distinctes se dessinent sur ${paramLabel} — scinder la question ou changer de référentiel ?` export const CRYSTALLIZE_CHOICES = ['Cristalliser quand même', 'Scinder', 'Reformuler'] as const export const CRYSTALLIZE_MODAL_DESC = "Tu figes d'un geste la position que le collectif dessine." // ── Record & observatory ── export const RECORD_ALT = 'Déjà tranché — je le consigne' export const RECORD_HOW = "Comment ça s'est décidé ?" export const OBSERVATORY_TITLE = "L'Observatoire" export const OBSERVATORY_SUBTITLE = 'comment nous décidons, dans les faits' export const REVOKED_SECTION = "Révoquées — ce qu'on en a appris" export const MATURATION_CARD = 'Cette pratique est mûre — protocolise-la en quelques phrases' // ── Élection ── export const BLANK_VOTE = 'Vote blanc' export const ELECTION_RULE = "La personne la plus désignée est nommée ; en cas d'égalité, vous départagez — jamais l'outil." // ── Urgence ── export const URGENT_TOGGLE = "C'est urgent" export const URGENT_BADGE = 'Décidé en urgence — le collectif ratifie' export const URGENT_REFUSED = "Irréversible : l'urgence ne peut pas contourner le collectif." // ── Fil / Aujourd'hui ── export const FEED_HEADER = 'À toi de décider' export const CAPTURE_PLACEHOLDER = "Qu'est-ce que tu décides ?" export const DOSSIER_COMPLETE_CARD = 'Le dossier est complet — clore et publier la cartographie de clôture' // ── Fiche / tunnel ── export const PATH_CARD_TITLE = 'Le chemin' export const CHOOSE_OTHERWISE = 'Je choisis autrement' export const WHY_DISCLOSURE = 'Pourquoi ?' export const ENGAGES_LABEL = 'Ce que ça engage' export const BASELINE_PREFIX = "Aujourd'hui :" export const BASELINE_ARROW = "Aujourd'hui → Proposé" export const INSTRUCT_BLOCK = "S'instruire" export const REOPEN_HANDLE = 'Remettre en question' export const ADOPTED_STAMP = 'Décidé' export const ADOPTED_TOAST = "C'est décidé — et révisable, comme tout ici." export const VOTE_PRIVACY = "Ton vote est remplaçable — ton historique n'est visible que de toi." export const WHO_VOTES = (n: number, date: string) => `Qui vote : ${n} personne${n > 1 ? 's' : ''} — liste arrêtée le ${date}` // ── Mandats ── export const MANDATES_TITLE = 'Mandats — les pouvoirs confiés' export const MANDATE_EXERCISE = 'Exercice du mandat' export const MANDATE_SPOTLIGHT = 'Feux de la rampe' export const MANDATE_SPOTLIGHT_SUB = 'toutes les décisions prises sous ce mandat — contestables' export const MANDATE_CLAIM = 'Réclamer un mandat' export const MANDATE_REVOKE = 'Demander la révocation' export const NOMINATION_LABELS: Record = { 'ratified-self': 'Auto-désignation ratifiée', 'election-no-candidate': 'Élection sans candidat', 'nuanced-vote': 'Vote nuancé', consent: 'Consentement', draw: 'Tirage au sort', rotation: 'Rotation', } // ── Textes / Pacte ── export const PACT_BADGE = 'les règles du jeu' export const PACT_SUBTITLE = 'Notre contrat social — sacralisé, jamais immuable' export const INERTIA_LABELS: Record = { low: 'inertie faible', standard: 'inertie standard', high: 'inertie haute', max: 'inertie maximale', } export const FIRST_DECISION = 'Adopter notre Pacte' export const CREATE_SIGNATURE = 'Osons, nous verrons' export const OPENING_DREAM = "Une démocratie qui n'a jamais existé — à votre échelle." export const CLOSING_LINE = 'La ville change, le puits demeure.' // ── Preuve / gravure / données ── export const PROOF_LOCAL = 'empreinte locale — démo' export const SECRET_DISPLAY = "secret d'affichage — démo" export const LINEAGE_PREFIX = 'essaimé de' export const WORKSHOP_MODE = 'mode atelier' export const WORKSHOP_RECORDED = (by: string, forWhom: string, date: string) => `saisi par ${by} pour ${forWhom} — atelier du ${date}` export const ATTRIBUTES_HINT = 'servent uniquement ta carte Pour moi, jamais montrés aux autres' export const SYNC_NOTE = 'Un serveur pourra se brancher plus tard, tes données ne changent pas de forme.' export const NO_PROTOCOL_BANNER = 'Aucun protocole — crée-le ou décide sur avis' // ── Génération des phrases de seuil (sujet = le collectif, jamais la formule) ── export const thresholdSentence = (W: number, T: number, threshold: number) => `${T.toLocaleString('fr-FR')} votant${T > 1 ? 's' : ''} sur ${W.toLocaleString('fr-FR')} : ` + `à si faible participation, il faut presque l'unanimité — ${threshold.toLocaleString('fr-FR')} pour. ` + 'Plus de monde vote, plus le seuil descend.'