From 59043920c4cfbcff0d08409e9afdaeec97b54941 Mon Sep 17 00:00:00 2001 From: Tomie <49788015+tomiet@users.noreply.github.com> Date: Sat, 11 Jul 2026 19:13:22 -0400 Subject: [PATCH 1/6] feat(web): add complete French UI translation catalogs Register fr alongside en with a full matching message inventory, keeping institutional crypto terms like Token short and stable for layout. Co-authored-by: Cursor --- apps/sdp-web/messages/fr.json | 28 + .../messages/fr/dashboard-custody.json | 404 ++++++++ .../messages/fr/dashboard-issuance.json | 867 +++++++++++++++++ .../messages/fr/dashboard-payments.json | 910 ++++++++++++++++++ apps/sdp-web/messages/fr/shared.json | 198 ++++ apps/sdp-web/src/i18n/README.md | 2 + apps/sdp-web/src/i18n/config.ts | 2 +- apps/sdp-web/src/i18n/messages.ts | 34 +- apps/sdp-web/src/i18n/messages.unit.test.ts | 32 +- 9 files changed, 2465 insertions(+), 12 deletions(-) create mode 100644 apps/sdp-web/messages/fr.json create mode 100644 apps/sdp-web/messages/fr/dashboard-custody.json create mode 100644 apps/sdp-web/messages/fr/dashboard-issuance.json create mode 100644 apps/sdp-web/messages/fr/dashboard-payments.json create mode 100644 apps/sdp-web/messages/fr/shared.json diff --git a/apps/sdp-web/messages/fr.json b/apps/sdp-web/messages/fr.json new file mode 100644 index 000000000..a6a0191a8 --- /dev/null +++ b/apps/sdp-web/messages/fr.json @@ -0,0 +1,28 @@ +{ + "Metadata": { + "title": "Solana Developer Platform", + "description": "Tableau de bord SDP" + }, + "Home": { + "solanaLogo": "Solana", + "docs": "Docs", + "dashboard": "Dashboard", + "title": "Construisez tout produit financier, sans gérer l’infrastructure", + "description": "Émission de stablecoin, paiements transfrontaliers ou tokenisation d’actifs réels : SDP fournit les APIs et l’infra les plus fiables pour y parvenir.", + "joinWaitlist": "Rejoindre la liste d’attente" + }, + "NotFound": { + "solanaLogo": "Solana", + "title": "Page introuvable", + "description": "Cette page n’existe pas ou a été déplacée.", + "backToDashboard": "Retour au dashboard", + "goHome": "Accueil" + }, + "Feedback": { + "label": "Feedback" + }, + "Error": { + "tryAgain": "Réessayer", + "reportIssue": "Signaler le problème" + } +} diff --git a/apps/sdp-web/messages/fr/dashboard-custody.json b/apps/sdp-web/messages/fr/dashboard-custody.json new file mode 100644 index 000000000..f13330ff3 --- /dev/null +++ b/apps/sdp-web/messages/fr/dashboard-custody.json @@ -0,0 +1,404 @@ +{ + "DashboardCustody": { + "actions": "Actions", + "rotateKey": "Rotation ({hours}h grâce)", + "deleteKey": "Supprimer la clé", + "actionFailed": "Échec de l’action", + "notice": "Avis", + "existingApiKeys": "Clés API existantes", + "apiKeysDescription": "Clés actives et historiques pour cet espace de travail.", + "newApiKey": "Nouvelle clé API", + "noApiKeysFound": "Aucune clé API trouvée.", + "name": "Nom", + "prefix": "Préfixe", + "access": "Accès", + "status": "Statut", + "lastUsed": "Dernière utilisation", + "expires": "Expire", + "created": "Créée", + "never": "Jamais", + "admin": "Admin", + "developer": "Developer", + "readOnly": "Lecture seule", + "allWallets": "Tous les Wallets", + "selectedWallets": "Wallets sélectionnés", + "selected": "{count} sélectionnés", + "selectedWallet": "Wallet sélectionné", + "selectedLabel": "Sélectionné", + "noApiKeyPolicy": "Aucune politique de clé API", + "noAdditionalApiKeyPolicy": "Aucune politique de clé API supplémentaire n’est associée.", + "policyBinding": "Association de politique", + "policyBindingCount": "{count} association de politique", + "policyBindingsCount": "{count} associations de politique", + "apiProfile": "Profil API {id}{revision}", + "walletProfile": "Profil Wallet {id}{revision}", + "revision": " rév. {id}", + "roleAccess": "Accès {role}", + "createApiKey": "Créer une clé API", + "reviewApiKey": "Vérifier la clé API", + "walletAccess": "Accès aux Wallets", + "walletAccessDescription": "Choisissez si cette clé peut utiliser tous les Wallets concernés ou seulement ceux sélectionnés.", + "allWalletsDescription": "Cette clé peut utiliser tous les Wallets de son org ou projet.", + "selectedWalletsDescription": "Limitez cette clé à des Wallets précis et choisissez son Wallet de signature par défaut.", + "operationPolicy": "Politique d’opération", + "noActiveWallets": "Aucun Wallet actif n’est encore disponible pour l’association.", + "defaultSigningWallet": "Wallet de signature par défaut", + "nameLabel": "Nom", + "namePlaceholder": "Clé de déploiement CI", + "role": "Rôle", + "environment": "Environnement", + "expirationOptional": "Expiration (facultatif)", + "production": "Production", + "sandbox": "Sandbox", + "none": "Aucun", + "invalidDate": "Date non valide", + "endpointPermissions": "Autorisations des endpoints", + "policy": "Politique", + "securityNote": "Note de sécurité", + "creating": "Création...", + "createKey": "Créer la clé", + "createApiKeyDescription": "Définissez les détails de la clé et l’accès aux Wallets, puis confirmez.", + "reviewApiKeyDescription": "Vérifiez la demande avant de créer la clé.", + "deleteApiKey": "Supprimer la clé API", + "deleteApiKeyPlaceholder": "Collez le nom exact de la clé", + "deleting": "Suppression...", + "deleteKeyConfirm": "Supprimer la clé", + "apiKeyGenerated": "Clé API générée", + "keyPrefix": "Préfixe de clé", + "fullKeyShownOnce": "Votre clé complète (affichée une seule fois)", + "apiKeyPlaygroundSession": "Cette session de navigateur peut désormais utiliser cette clé dans l’API Playground sans la recoller.", + "dismiss": "Fermer", + "copyValue": "Copier", + "copied": "Copié", + "closeGeneratedKeyModal": "Fermer la modale de clé générée", + "closeConfirmationModal": "Fermer la modale de confirmation", + "delete": "Supprimer", + "deleteApiKeyDescription": "Cela supprime la clé sans supprimer la ligne.", + "typeKeyNameToConfirm": "Saisissez {name} pour confirmer.", + "confirmKeyName": "Confirmer le nom de la clé", + "cancel": "Annuler", + "waitingForOrganizationSync": "En attente de synchronisation de l’organisation", + "organizationSyncDescription": "SDP attend que le webhook Clerk crée le mappage de cette organisation.", + "organizationSyncHelp": "Création d’orga et sync membres via webhooks Clerk uniquement. Actualisez ; si ça persiste, vérifiez le webhook Clerk.", + "organizationName": "Nom de l’organisation", + "organizationSlug": "Slug de l’organisation", + "clerkOrganizationId": "ID d’organisation Clerk", + "unavailable": "Indisponible", + "unableToLoadWalletProviders": "Impossible de charger les fournisseurs de Wallet", + "unableToLoadWallets": "Impossible de charger les Wallets", + "trackedBalancesUnavailable": "Les soldes suivis sont indisponibles pour le moment. Affichage du solde indiqué par le Wallet.", + "walletControlsUnavailable": "Les contrôles du Wallet sont indisponibles pour le moment.", + "createWallet": "Créer un Wallet", + "wallet": "Wallet", + "balance": "Solde", + "purpose": "Usage", + "issuance": "Émission", + "compliance": "Conformité", + "mintAuthority": "Autorité de Mint", + "freezeAuthority": "Autorité de Freeze", + "feePayer": "Fee payer", + "transfers": "Transferts", + "address": "Adresse", + "walletId": "ID du Wallet", + "manage": "Gérer", + "createFirstWallet": "Créez votre premier Wallet", + "noWalletsAvailable": "Aucun Wallet disponible", + "createWalletDescription": "Choisissez le fournisseur qui créera et signera pour le Wallet.", + "walletCreationLimited": "La création de Wallet est limitée aux Admins. Une fois créé, vous pouvez toujours utiliser un Wallet dans le tableau de bord.", + "noWalletProvidersEnabled": "Aucun fournisseur de Wallet activé", + "noWalletProvidersEnabledDescription": "Activez un fournisseur pour cette organisation avant de créer un Wallet.", + "backToWallets": "Retour aux Wallets", + "chooseProvider": "Choisir un fournisseur", + "walletDetails": "Détails du Wallet", + "walletLabel": "Libellé du Wallet", + "walletLabelPlaceholder": "Trésorerie", + "project": "Projet", + "projectValue": "Projet actuel", + "environmentValue": "Environnement actuel", + "connectedProviderDescription": "{provider} utilise son Wallet déjà configuré dans ce flux.", + "chooseEnabledProvider": "Choisissez un fournisseur activé pour continuer.", + "back": "Retour", + "continue": "Continuer", + "createWalletPending": "Création...", + "saveWalletLabel": "Enregistrer le libellé du Wallet", + "cancelWalletLabelEdit": "Annuler la modification du libellé", + "editWalletLabel": "Modifier le libellé du Wallet", + "untitled": "Sans titre", + "updatingWalletLabel": "Mise à jour du libellé du Wallet.", + "walletLabelUpdated": "Libellé du Wallet mis à jour.", + "unableToUpdateWalletLabel": "Impossible de mettre à jour le libellé du Wallet.", + "unknownError": "Erreur inconnue", + "requestFailed": "Échec de la requête", + "httpRequestFailed": "{error} (HTTP {status})", + "walletIdRequired": "L’ID du Wallet est requis.", + "validWalletAddressRequired": "Une adresse de Wallet valide est requise.", + "signInToRequestDevnetSol": "Connectez-vous pour demander des SOL Devnet.", + "devnetFaucetHttpError": "Le fournisseur RPC du faucet Devnet {provider} a renvoyé HTTP {status}.", + "devnetFaucetEmptyResponse": "Le faucet Devnet a renvoyé une réponse RPC vide.", + "devnetFaucetProviderError": "Le fournisseur RPC du faucet Devnet {provider} a renvoyé : {error}", + "devnetFaucetProviderGenericError": "Le fournisseur RPC du faucet Devnet {provider} a renvoyé une erreur.", + "devnetFaucetNoSignature": "Le faucet Devnet n’a renvoyé aucune Signature de transaction.", + "walletAddress": "Adresse du Wallet", + "walletMetadataCopied": "{label} copié.", + "unableToCopy": "Impossible de copier {label}.", + "copy": "Copier {label}", + "recentActivity": "Activité récente", + "recentActivityDescription": "Activité de transfert et d’opérations de Token pour ce Wallet.", + "refreshing": "Actualisation...", + "refresh": "Actualiser", + "noWalletActivity": "Aucune activité de Wallet trouvée.", + "activity": "Activité", + "asset": "Asset", + "direction": "Sens", + "counterparty": "Counterparty", + "signature": "Signature", + "unknownAsset": "Asset inconnu", + "unknown": "Inconnu", + "pending": "En attente", + "incoming": "Entrant", + "outgoing": "Sortant", + "transfer": "Transfert", + "unableToLoadIssuanceActivity": "Impossible de charger l’activité d’émission", + "paymentsActivityUnavailable": "L’activité des paiements est indisponible pour le moment.", + "issuanceActivityUnavailable": "L’activité d’émission est indisponible pour le moment.", + "noActivitySources": "Aucune source d’activité n’est disponible pour ce Wallet.", + "walletActivityUnavailable": "L’activité du Wallet est indisponible pour le moment.", + "unableToVerifyWalletVisibility": "Impossible de vérifier la visibilité du Wallet.", + "invalidWalletId": "ID de Wallet non valide.", + "walletActivityRequestFailed": "Échec de la requête d’activité du Wallet.", + "previous": "Précédent", + "active": "Actif", + "noWalletProvidersTier": "Aucun fournisseur de Wallet n’est activé pour ce niveau d’organisation pour le moment.", + "newWallet": "Nouveau Wallet", + "providerAdditionalWalletUnavailable": "{provider} est déjà connecté, mais les Wallets supplémentaires ne sont pas encore disponibles.", + "walletCreationAvailable": "La création de Wallet est disponible après l’activation d’un fournisseur de custody pour cette organisation.", + "stale": "(obsolète)", + "organizationSettings": "Paramètres de l’organisation", + "organizationSettingsDescription": "Configurez le fournisseur RPC utilisé dans cette organisation.", + "failedToLoadOrganizationSettings": "Échec du chargement des paramètres de l’organisation.", + "organizationNotFound": "Organisation introuvable.", + "organizationNotLinked": "Cette organisation Clerk n’est pas encore liée à une organisation SDP.", + "editingOrganization": "Modification de l’organisation : {name}", + "viewOnlyRpcSettings": "Vous pouvez voir les paramètres RPC de l’organisation, mais seuls les Admins peuvent les modifier.", + "noRpcProviders": "Aucun fournisseur RPC n’est activé pour cette organisation dans l’environnement actuel.", + "rpcFallback": "Le fournisseur RPC enregistré pour cette organisation n’est plus disponible au niveau actuel. Le formulaire utilise {provider} jusqu’à l’enregistrement d’un fournisseur activé.", + "saving": "Enregistrement...", + "saveFallback": "Enregistrer le secours", + "rpcProvider": "Fournisseur RPC", + "testing": "Test...", + "testRpc": "Tester RPC", + "saveInProgress": "Enregistrement en cours.", + "tryAgainSoon": "Réessayez dans un instant.", + "checkingRpcProvider": "Vérification du fournisseur RPC.", + "rpcCheckPassed": "Vérification RPC réussie.", + "providerMismatch": "Fournisseur non correspondant.", + "rpcCheckFailed": "Échec de la vérification RPC.", + "anotherProvider": "un autre fournisseur", + "failedToSaveRpcSettings": "Échec de l’enregistrement des paramètres RPC.", + "missingOrganizationId": "ID d’organisation manquant.", + "rpcProviderSaveMismatch": "Incohérence d’enregistrement du fournisseur RPC (demandé : {requested}, enregistré : {persisted}).", + "rpcSettingsSaved": "Paramètres RPC enregistrés.", + "failedToTestRpcProvider": "Échec du test du fournisseur RPC.", + "rpcTestFailed": "Échec du test RPC.", + "rpcTestFailedStatus": "Échec du test RPC ({status}).", + "rpcTestMismatch": "Incohérence du test RPC (demandé : {requested}, résolu : {resolved}).", + "rpcUpstreamReturned": "L’amont RPC a renvoyé {status} {statusText}.", + "rpcTestPassed": "Test RPC réussi ({status} {statusText}) en {latency} ms.", + "missingApiKeyIdForDeletion": "ID de clé API manquant pour la suppression.", + "missingApiKeyNameForDeletion": "Nom de clé API manquant pour confirmer la suppression.", + "confirmApiKeyDeletion": "Saisissez le nom de la clé pour confirmer la suppression de la clé API.", + "apiKeyConfirmationMismatch": "La confirmation ne correspond pas au nom de la clé.", + "apiKeyDeactivated": "La clé API « {name} » a été désactivée.", + "apiKeyDeleteFailed": "Échec de la suppression : {error}", + "apiKeyNameRequired": "Le nom de la clé API est requis.", + "apiKeyWalletScopeRequired": "Choisissez si cette clé peut accéder à tous les Wallets ou aux Wallets sélectionnés.", + "apiKeyWalletRequired": "Sélectionnez au moins un Wallet pour une clé API limitée à un Wallet.", + "invalidExpirationDate": "Date d’expiration non valide.", + "apiKeyCreated": "Clé API « {name} » créée. Enregistrez-la maintenant ; elle ne sera plus affichée.", + "apiKeyCreateFailed": "Échec de la création : {error}", + "missingApiKeyIdForRotation": "ID de clé API manquant pour la rotation.", + "apiKeyRotated": "Clé API renouvelée. La clé précédente reste valide jusqu’au {deadline}.", + "apiKeyRotateFailed": "Échec de la rotation : {error}", + "providerLocalDescription": "Signer de paire de clés Ed25519 auto-hébergée depuis CUSTODY_PRIVATE_KEY.", + "providerPrivyDescription": "Infrastructure de Wallet hébergée pour la signature API.", + "providerFireblocksDescription": "Custody MPC avec contrôles de Wallet basés sur les vaults.", + "providerCoinbaseCdpDescription": "Provisionnement programmatique de Wallet via Coinbase CDP.", + "providerParaDescription": "Custody de Wallet intégré pour les opérations au niveau de l’organisation.", + "providerTurnkeyDescription": "Custody de clés fondée sur des politiques pour les charges de signature de production.", + "providerDfnsDescription": "Orchestration de Wallet MPC avec signature sécurisée pilotée par API.", + "providerIbmHavenDescription": "Custody institutionnelle sur IBM Digital Asset Haven.", + "providerAnchorageDescription": "Custody institutionnelle avec gestion du cycle de vie des Wallets.", + "providerUtilaDescription": "Signature de Wallet Solana adossée à un vault via les comptes de service Utila.", + "apiKeyAdminDescription": "Admin inclut les privilèges de custody et de plateforme. Developer exclut les actions de custody.", + "apiKeyEnvironmentDescription": "Changez l’environnement de l’espace de travail dans la barre latérale pour créer une clé dans l’autre environnement.", + "expiresOn": "Expire le {date}", + "default": "Par défaut :", + "fullKeyOnlyShownOnce": "La clé complète ne sera affichée qu’une fois après sa création.", + "closeApiKeyCreationModal": "Fermer la modale de création de clé API", + "policyDraftSaveFailed": "Le Draft n’a pas pu être enregistré.", + "policyDraftSaveFailedDescription": "Vous pouvez continuer, mais les changements peuvent être perdus si vous quittez.", + "policyDraftSaved": "Draft enregistré.", + "policyDraftSavedDescription": "Le profil n’est pas encore actif.", + "policyChooseRestriction": "Choisissez au moins une catégorie de restriction.", + "policyCheckDestinations": "Vérifiez les adresses de destination.", + "policyCheckDestinationsDescription": "Utilisez des adresses Solana valides avant la vérification.", + "policyChooseOperations": "Choisissez les contrôles d’accès aux opérations.", + "policyChooseOperationsDescription": "Sélectionnez au moins une famille d’opérations à bloquer.", + "policyCheckLimits": "Vérifiez les limites de transfert.", + "policyCheckLimitsDescription": "Saisissez un nombre positif pour chaque limite configurée.", + "policyChooseApprovals": "Choisissez les contrôles d’approbation.", + "policyChooseApprovalsDescription": "Sélectionnez au moins une famille d’opérations nécessitant une approbation.", + "policyChooseAdvanced": "Choisissez les contrôles de signature avancés.", + "policyChooseAdvancedDescription": "Sélectionnez la signature brute, les interactions de programme, ou les deux.", + "policyActivating": "Activation des contrôles du Wallet.", + "policyActive": "Contrôles du Wallet actifs.", + "policyActiveDescription": "Les restrictions sélectionnées sont maintenant actives.", + "policyActivationFailed": "Échec de l’activation.", + "policySaveFailed": "Les contrôles du Wallet n’ont pas pu être enregistrés.", + "policyDisabling": "Désactivation des contrôles du Wallet.", + "policyDisabled": "Contrôles du Wallet désactivés.", + "policyDisabledDescription": "Le Wallet revient à l’autorisation par défaut.", + "policyDisableFailed": "Échec de la désactivation.", + "wallets": "Wallets", + "playgroundListWallets": "Lister les Wallets", + "playgroundListWalletConfigs": "Lister les configurations de Wallet", + "playgroundGetWallet": "Obtenir le Wallet", + "playgroundGetWalletPublicKey": "Obtenir la clé publique du Wallet", + "playgroundAggregateBalances": "Agréger les soldes des Wallets", + "playgroundCreateWallet": "Créer un Wallet", + "playgroundSignerCheck": "Vérification du Signer", + "rootWallet": "Wallet racine", + "mainWallet": "Wallet principal", + "mainSettlementWallet": "Wallet principal de règlement", + "selectWalletPurpose": "Sélectionner l’usage du Wallet", + "ownershipProof": "Preuve de propriété depuis le playground Wallet", + "untitledWallet": "Wallet sans titre", + "publicKey": "Clé publique", + "provider": "Fournisseur", + "totalBalance": "Solde total", + "balances": "Soldes", + "noTrackedBalances": "Aucun solde suivi trouvé pour ce Wallet.", + "walletControls": "Contrôles du Wallet", + "walletRestrictionsActive": "Ce Wallet a des restrictions actives sur les paiements sortants.", + "walletDefaultAllow": "Ce Wallet démarre en allow par défaut. Ajoutez des restrictions seulement si besoin.", + "destinations": "Destinations", + "open": "Ouvrir", + "perTransfer": "Par transfert", + "daily": "Quotidien", + "noCap": "Aucun plafond", + "reviewControls": "Vérifier les contrôles", + "startProfile": "Démarrer le profil", + "policyIntent": "Intention", + "policySetWalletPolicies": "Définir les politiques de Wallet", + "policyIntentDescription": "Choisissez où les fonds peuvent aller et combien ce Wallet peut transférer.", + "policyRules": "Règles", + "policyStartingRules": "Règles initiales", + "policyRulesDescription": "Configurez les zones de règles sélectionnées avant vérification.", + "policyReview": "Vérification", + "policyFinalReview": "Vérification finale", + "policyReviewDescription": "Vérifiez les changements avant d’appliquer les contrôles du Wallet.", + "policyOperationAccess": "Accès aux opérations", + "policyOperationAccessDescription": "Bloquez les familles d’opérations à risque tout en conservant l’usage normal.", + "policyAllowedDestinations": "Destinations autorisées", + "policyAllowedDestinationsDescription": "À utiliser lorsque ce Wallet ne doit payer que des adresses connues.", + "policyTransferLimits": "Limites de transfert", + "policyTransferLimitsDescription": "À utiliser lorsque ce Wallet requiert des plafonds de dépense ou de sortie quotidienne.", + "policyApprovalChecks": "Contrôles d’approbation", + "policyApprovalChecksDescription": "Suspendez les familles d’opérations sélectionnées pour approbation avant exécution.", + "policyAdvancedSigning": "Signature avancée", + "policyAdvancedSigningDescription": "Limitez la signature brute et les interactions directes avec les programmes.", + "policyPayments": "Paiements", + "policyRamps": "Ramps", + "policyIssuance": "Émission", + "policyProviderAdmin": "Admin fournisseur", + "policyRawSigning": "Signature brute", + "policyProgramInteractions": "Interactions de programme", + "policyAllowed": "Autorisé", + "policyDenied": "Refusé", + "policyApprovalRequired": "Approbation requise", + "policyProviderApprovalRequired": "Approbation du fournisseur requise", + "policyNotEvaluated": "Non évalué", + "policyFailed": "Échec", + "recentPolicyDecisions": "Décisions de politique récentes", + "policyEvaluationsShown": "{count} évaluations affichées pour ce Wallet", + "needsApproval": "Nécessite une approbation", + "stepOf": "Étape {current} sur {total}", + "collapse": "Réduire", + "expand": "Développer", + "policyActivationOutcome": "Résultat de l’activation", + "policyDefault": "Par défaut", + "policyAllowUnmatched": "Autoriser les opérations sans correspondance", + "policyRevision": "Révision", + "policyProviderMapping": "Mappage du fournisseur", + "policySdpEnforced": "Appliqué par SDP", + "policyNoRestrictionCategory": "Aucune catégorie de restriction sélectionnée.", + "policyNoOperationsBlocked": "Aucune famille d’opérations bloquée", + "policyNoAddresses": "Aucune adresse", + "policyNoApprovalChecks": "Aucun contrôle d’approbation", + "policyNoAdvancedControls": "Aucun contrôle de signature avancé", + "savedDraft": "Draft enregistré", + "policyApplyControls": "Appliquer les contrôles", + "policyChooseOperationFamilies": "Choisissez les familles d’opérations à bloquer.", + "policyPasteAddresses": "Collez les adresses Solana approuvées ou une colonne d’adresses CSV.", + "policySetCaps": "Définissez un plafond par transfert, quotidien, ou les deux.", + "policyChooseApprovalFamilies": "Choisissez les familles d’opérations devant être suspendues pour approbation.", + "policyBlockAdvanced": "Bloquez la signature brute, les interactions de programme, ou les deux.", + "new": "Nouveau", + "policyProviderMappingPending": "Mappage du fournisseur en attente", + "policyProviderMapped": "Fournisseur mappé", + "policyProviderPartiallyMapped": "Fournisseur partiellement mappé", + "policyProviderMappingFailed": "Échec du mappage du fournisseur", + "policyBlockFamilies": "Bloquer {families}", + "policyRequireApprovalFor": "Exiger une approbation pour {families}", + "policyDenyFamilies": "Refuser {families}", + "policyDestinationCount": "{count} adresses", + "policyInvalidCount": "{count} non valides", + "policyAllowedCount": "{count} autorisées", + "policyPerTransferValue": "Par transfert : {value}", + "policyDailyValue": "Quotidien : {value}", + "sandboxProjectUnavailable": "Projet Sandbox indisponible. Rechargez le tableau de bord et réessayez.", + "sendingSignerCheck": "Envoi de la vérification du Signer.", + "signerCheckFailed": "Échec de la vérification du Signer.", + "signerCheckSent": "Vérification du Signer envoyée.", + "memoTransactionSubmitted": "Transaction Memo soumise.", + "viewOnSolanaExplorer": "Voir dans Solana Explorer", + "requestingDevnetSol": "Demande de SOL Devnet.", + "devnetFaucetFailed": "Échec du faucet Devnet.", + "devnetSolRequested": "{amount} SOL Devnet demandés.", + "faucetTransactionSubmitted": "Transaction du faucet soumise.", + "walletActionsFor": "Actions du Wallet pour {wallet}", + "proving": "Preuve...", + "proveOwnershipUnsupported": "Prouver la propriété (non pris en charge)", + "proveOwnership": "Prouver la propriété", + "proveOwnershipAdminOnly": "Prouver la propriété (Admin uniquement)", + "requesting": "Demande...", + "requestDevnetSol": "Demander des SOL Devnet", + "policyRuleAllowedDestinations": "Destinations autorisées", + "policyRulePerTransferLimit": "Limite par transfert", + "policyRuleApprovalChecks": "Contrôles d’approbation", + "policyRevisionNew": "Nouveau", + "policyPerTransferCap": "Plafond par transfert", + "policyDailyCap": "Plafond quotidien", + "policyPositiveNumber": "Saisissez un nombre positif.", + "policyAddressPlaceholder": "adresse 9xQeWvG816bUx9EPfuxEzHh9VY5k...", + "policyDisable": "Désactiver", + "policyApprovalRequest": " / Approbation {id}", + "playgroundProviderField": "Fournisseur", + "playgroundLabelField": "Libellé", + "playgroundPurposeField": "Usage", + "playgroundMemoField": "Memo", + "policyOperationEditorDescription": "Les familles sélectionnées sont refusées avant signature/exécution. Les autres restent en allow par défaut sauf autre règle.", + "policyDestinationEditorDescription": "Collez des adresses Solana séparées par des sauts de ligne, virgules, points-virgules, tabulations ou une colonne CSV.", + "policyInvalidAddress": "Adresse non valide : {addresses}", + "policyInvalidAddresses": "Adresses non valides : {addresses}", + "policyApprovalEditorDescription": "Les familles sélectionnées sont mises en pause (approbation requise). Le routage inbox est géré par le workflow d’approbation.", + "policyAdvancedEditorDescription": "Ces contrôles sont volontairement stricts, car ils peuvent contourner l’intention de paiement de haut niveau.", + "providerCategoryApi": "API", + "providerCategoryApiDescription": "Infrastructure de Wallet pour les flux produit, opérationnels et automatisés pilotés par API.", + "providerCategoryInstitutional": "Institutionnel", + "providerCategoryInstitutionalDescription": "Custody politique pour trésorerie, settlement et approbations multiparty.", + "existingApiKeysDescription": "Clés actives et historiques pour cet espace de travail.", + "apiKeysViewOnly": "Vous pouvez voir les clés API, mais seuls les Admins peuvent les créer, renouveler ou supprimer.", + "apiKeyRotationHint": "Conseil : ne rotatez que les clés actives. Grâce dashboard 24 h ; API pour 0–168 h. Nouveau secret affiché une fois." + } +} diff --git a/apps/sdp-web/messages/fr/dashboard-issuance.json b/apps/sdp-web/messages/fr/dashboard-issuance.json new file mode 100644 index 000000000..40d536234 --- /dev/null +++ b/apps/sdp-web/messages/fr/dashboard-issuance.json @@ -0,0 +1,867 @@ +{ + "DashboardIssuance": { + "transactions": { + "title": "Transactions", + "description": "Opérations Token récentes", + "loading": "Chargement de l'historique des opérations…", + "empty": "Aucune transaction.", + "type": "Type", + "status": "Statut", + "signature": "Signature", + "created": "Créé", + "showing": "Affichage des {count} premières transactions{total}. Utilisez la pagination pour voir les anciennes." + }, + "errors": { + "unknown": "Erreur inconnue", + "requestFailed": "Échec de la demande", + "unavailable": "indisponible", + "apiRequestFailed": "{resource} API {status} : {error}", + "tokenResource": "Token", + "templateResource": "Template", + "walletResource": "Wallet", + "tokenListRetry": "Impossible de charger la liste des Token. Actualisez la page pour réessayer.", + "tokenListCreateOrRetry": "Impossible de charger la liste des Token. Vous pouvez créer un Token ou réessayer bientôt.", + "unableToLoadTemplates": "Impossible de charger les Templates", + "unableToLoadTokens": "Impossible de charger les Token", + "unableToLoadSignerWallets": "Impossible de charger les Wallets Signer.", + "mintUnavailable": "Mint indisponible — {reason}", + "burnUnavailable": "Burn indisponible — {reason}", + "assetProfileNotFound": "Profil Asset introuvable.", + "assetProfileLoadFailed": "Impossible de charger le profil Asset ({status}) : {error}", + "tokenDetailsSaveFailed": "Impossible d'enregistrer les détails du Token ({status}) : {error}", + "assetProfileUpdateFailed": "Les détails du Token sont enregistrés, mais la mise à jour du profil Asset a échoué ({status}) : {error}. Réessayez.", + "changesSaved": "Modifications enregistrées.", + "unableToSaveChanges": "Impossible d'enregistrer les modifications.", + "assetProfilesDisabled": "Les profils Asset ne sont pas activés pour cet environnement.", + "assetDraftCreateFailed": "Impossible de créer le Draft Asset ({status}) : {error}", + "assetDraftCreated": "Draft Asset créé.", + "unableToCreateAssetDraft": "Impossible de créer le Draft Asset.", + "metadataUriHttp": "L'URI des métadonnées doit utiliser http ou https.", + "metadataUriValid": "L'URI des métadonnées doit être une URL valide.", + "tokenNameRequired": "Le nom du Token est requis.", + "symbolFormat": "Le symbole doit compter 1 à 10 caractères : lettres, chiffres ou points.", + "invalidTemplate": "Sélection de Template invalide.", + "decimalsRange": "Decimals doit être compris entre 0 et 18.", + "createFailed": "Échec de création ({status}) : {error}", + "draftCreated": "Draft {name} créé. Deploy Onchain depuis la page Token.", + "unexpected": "Erreur inattendue", + "symbolRequired": "Le symbole est requis.", + "symbolCharacters": "Utilisez 1 à 10 lettres, chiffres ou points.", + "decimalsWholeNumber": "Saisissez un nombre entier entre 0 et 18.", + "descriptionRequired": "La description est requise.", + "validUrl": "Saisissez une URL valide (https://…).", + "fieldRequired": "{field} est requis.", + "field": "Champ", + "classificationRequired": "Choisissez une classification et un sous-type d'Asset.", + "assetNameRequired": "Le nom de l'Asset est requis." + }, + "controlLists": { + "title": "Listes de contrôle", + "controlList": "Liste de contrôle", + "entriesTitle": "Entrées {label}", + "descriptionWithList": "Entrées {label} et statut des comptes Freeze", + "descriptionWithoutList": "Statut des comptes Freeze", + "entriesCount": "{count} entrées", + "showingEntries": "Affichage des {count} premières entrées.", + "frozenAccounts": "Comptes Freeze", + "accountsCount": "{count} comptes", + "showingAccounts": "Affichage des {count} premiers comptes." + }, + "wallet": { + "none": "Aucun", + "unlabeled": "Wallet sans libellé", + "walletId": "ID Wallet", + "publicKey": "Clé publique", + "customAddress": "Adresse personnalisée", + "chooseOrPaste": "Choisissez un Wallet ou collez une adresse Solana", + "clear": "Effacer {label}", + "selectExisting": "Sélectionner un Wallet existant", + "filterHint": "Saisissez pour filtrer les Wallets, utilisez la liste ou collez une adresse Solana." + }, + "saveBar": { + "unsaved": "Vous avez des modifications non enregistrées", + "unsavedWithErrors": "Modifications non enregistrées — {count} champ{suffix} à vérifier", + "discard": "Ignorer", + "save": "Enregistrer", + "saving": "Enregistrement…" + }, + "confirmation": { + "notNow": "Pas maintenant" + }, + "modal": { + "close": "Fermer la fenêtre", + "closeConfirmation": "Fermer la confirmation", + "tokenManagementAction": "Action de gestion du Token" + }, + "signer": { + "label": "Signer", + "select": "Sélectionner un Wallet Signer", + "requiredAuthorityHint": "SDP signera cette action avec le Wallet de l'autorité requise.", + "selectedWalletHint": "SDP signera cette transaction avec le Wallet sélectionné.", + "defaultSignerHint": "Aucun Wallet Signer disponible — SDP utilisera le Signer par défaut du projet.", + "noneAvailable": "Aucun Wallet Signer disponible." + }, + "header": { + "tokenLogo": "Logo du Token {name}", + "notDeployed": "Non Deploy", + "copyTokenAddress": "Copier l'adresse du Token", + "tokenId": "ID Token", + "copyTokenId": "Copier l'ID Token", + "explorer": "Explorer", + "deploy": "Deploy", + "unpause": "Unpause" + }, + "create": { + "title": "Nouveau brouillon Token", + "closeModal": "Fermer la création de Token", + "createDraft": "Créer le Draft", + "requiredFields": "Les champs marqués * sont requis.", + "required": "(requis)", + "tokenName": "Nom du Token", + "tokenNamePlaceholder": "ex. USD Coin", + "symbol": "Symbole", + "symbolPlaceholder": "ex. USDC", + "decimals": "Decimals", + "decimalsPlaceholder": "ex. 6", + "decimalsError": "Saisissez un nombre entier entre 0 et 18.", + "stablecoinDecimalsHelper": "Stablecoin utilise 6 Decimals par défaut, mais vous pouvez choisir de 0 à 18.", + "customDecimalsHelper": "Les Token personnalisés utilisent 9 Decimals par défaut. Choisissez de 0 à 18.", + "tokenizedSecurityDecimalsHelper": "Tokenized Security utilise 8 Decimals par défaut, mais vous pouvez choisir de 0 à 18.", + "decimalsHelper": "Choisissez une valeur de 0 à 18.", + "back": "Retour", + "continue": "Continuer", + "mainSigner": "Signer principal", + "selectSignerWallet": "Sélectionner le Wallet Signer", + "mainSignerHint": "Ce Wallet sera le Signer principal du Token pour le Deploy et les actions ultérieures.", + "loadingSignerWallets": "Chargement des Wallets Signer…", + "noControlledWallets": "Aucun Wallet contrôlé disponible. Le Token utilisera le Signer par défaut.", + "transferControls": "Contrôles de transfert", + "transferControlsHint": "Choisissez le traitement des adresses de destination approuvées ou bloquées.", + "creating": "Création...", + "creatingDraft": "Création du Draft Token.", + "unableToLoadSignerWallets": "Impossible de charger les Wallets Signer.", + "unableToCreateDraft": "Impossible de créer le Draft Token.", + "draftCreated": "Draft créé. Deploy Onchain depuis la page Token.", + "configureDraft": "Configurez le Draft, puis Deploy Onchain depuis la page Token.", + "chooseTemplate": "Choisissez un Template pour créer un Draft, puis Deploy Onchain.", + "stablecoinTemplateName": "Stablecoin", + "tokenizedSecurityTemplateName": "Tokenized Security", + "customTemplateName": "Token personnalisé", + "stablecoinTemplateDescription": "Créez un Stablecoin conforme avec restrictions de transfert.", + "tokenizedSecurityTemplateDescription": "Créez un Tokenized Security conforme avec Scaled UI Amount et contrôles essentiels.", + "customTemplateDescription": "Créez votre Token avec contrôle total des extensions et paramètres.", + "createStablecoinDraft": "Créer un Draft Stablecoin", + "createTokenizedSecurityDraft": "Créer un Draft Tokenized Security", + "createCustomTokenDraft": "Créer un Draft Token personnalisé", + "createTokenDraft": "Créer un Draft Token", + "denylist": "Denylist", + "allowlist": "Allowlist", + "disabled": "Désactivé", + "denylistDescription": "Les destinations listées sont bloquées avant de recevoir des actions contrôlées.", + "allowlistDescription": "Seules les destinations approuvées peuvent recevoir des actions Token contrôlées.", + "disabledDescription": "Ce Token n'utilisera pas de liste de contrôle des transferts.", + "stablecoinDenylistNote": "Recommandé par défaut pour les Stablecoin.", + "stablecoinAllowlistNote": "À utiliser si les transferts doivent rester entre Wallets connus.", + "securityAllowlistNote": "Par défaut pour les Tokenized Security.", + "securityDenylistNote": "À utiliser si le Token reste ouvert sauf pour les Wallets bloqués.", + "customDisabledNote": "Idéal pour les Token personnalisés sans restriction.", + "customAllowlistNote": "Activez si le Token exige un accès de transfert restreint." + }, + "status": { + "draft": "Draft", + "active": "Actif", + "paused": "En pause", + "revoked": "Révoqué" + }, + "tabs": { + "overview": "Aperçu", + "details": "Détails", + "publicInformation": "Informations publiques", + "compliance": "Conformité", + "operations": "Opérations", + "permissions": "Permissions" + }, + "workspace": { + "tokenLoadWarning": "Avertissement de chargement du Token", + "tokenPaused": "Le Token est en pause", + "pausedHint": "Les actions Mint, Burn et transfert administratif sont désactivées jusqu'à Unpause du Token.", + "unpauseToken": "Unpause Token", + "deployToken": "Deploy Token", + "deployHint": "Ceci va Deploy le Token Onchain pour permettre les opérations.", + "cancel": "Annuler", + "deployNow": "Deploy maintenant", + "runningAction": "Exécution de l'action...", + "tokenListUnavailable": "Liste des Token indisponible", + "search": "Rechercher", + "createDraft": "Créer un Draft", + "noTokensMatch": "Aucun Token ne correspond à votre recherche.", + "tokenLogo": "Logo {name}", + "type": "Type", + "supply": "Supply", + "created": "Créé", + "manage": "Gérer", + "addNewToken": "Ajouter un Token", + "active": "Actif", + "draft": "Draft" + }, + "management": { + "tokenAmountDescription": "Unités Token (ex. 1 ou 1,5). Conversion en unités brutes selon les Decimals.", + "untitledToken": "Token sans titre", + "allowlist": "Allowlist", + "denylist": "Denylist", + "allowlistDescription": "Gérez les adresses de destination approuvées pour ce Token.", + "denylistDescription": "Gérez les adresses de destination bloquées pour ce Token.", + "allowlistSummaryDescription": "Entrées Allowlist et statut des comptes Freeze", + "denylistSummaryDescription": "Entrées Denylist et statut des comptes Freeze", + "allowlistEntries": "Entrées Allowlist", + "denylistEntries": "Entrées Denylist", + "addAllowlistEntry": "Ajouter une entrée Allowlist", + "addDenylistEntry": "Ajouter une entrée Denylist", + "removeEntry": "Supprimer l'entrée", + "noAllowlistEntries": "Aucune entrée Allowlist.", + "noDenylistEntries": "Aucune entrée Denylist.", + "allowlistAddressRequired": "L'adresse Allowlist est requise.", + "denylistAddressRequired": "L'adresse Denylist est requise.", + "allowlistExtensionHelper": "Les destinations Mint et de transfert contrôlé doivent être dans l'Allowlist du Token.", + "denylistExtensionHelper": "Les destinations listées sont bloquées pour les opérations Mint et de transfert contrôlé.", + "denylistFreezeHint": "Restreindre un Wallet avant son compte Token ? Ajoutez-le d'abord à la Denylist.", + "defaultAccountState": "État de compte par défaut", + "defaultAccountStateHelper": "État par défaut des nouveaux comptes Token.", + "transferFee": "Frais de transfert", + "transferFeeHelper": "Configuration des frais pour les transferts Token.", + "scaledUiAmount": "Scaled UI Amount", + "scaledUiAmountHelper": "Contrôles du multiplicateur de Supply UI.", + "transferHook": "Transfer Hook", + "transferHookHelper": "Hook de programme de logique de transfert personnalisée.", + "interestBearing": "Interest Bearing", + "interestBearingHelper": "Mises à jour de solde basées sur le taux d'intérêt.", + "nonTransferable": "Non transférable", + "nonTransferableHelper": "Désactive les transferts standard entre comptes.", + "template": "Template", + "templateHelper": "Template de base appliqué à ce Token.", + "mintable": "Compatible Mint", + "mintableHelper": "Autorise les opérations Mint après Deploy.", + "freezable": "Compatible Freeze", + "freezableHelper": "Autorise les contrôles Freeze/Unfreeze des comptes.", + "configured": "Configuré", + "enabled": "Activé", + "disabled": "Désactivé", + "overview": "Aperçu", + "permissions": "Permissions", + "permissionsDescription": "Clés Onchain contrôlant Mint, Freeze et métadonnées de ce Token.", + "extensions": "Extensions", + "extensionsDescription": "Configurées à la création et en lecture seule après Deploy.", + "edit": "Modifier", + "compliance": "Conformité", + "metadata": "Métadonnées", + "operations": "Opérations", + "mintTokens": "Mint Tokens", + "mintHelper": "Créez une nouvelle Supply dans un Wallet ou compte Token de destination.", + "mint": "Mint", + "burnTokens": "Burn Tokens", + "burnHelper": "Retirez la Supply d'un Wallet ou compte Token source.", + "burn": "Burn", + "unableToLoadData": "Impossible de charger les données de gestion du Token.", + "supportingDataRequestFailed": "Échec de la demande de données Token ({status}).", + "supportingDataEmpty": "La réponse des données Token était vide.", + "authorityWalletRequestFailed": "Échec de la demande du Wallet d'autorité ({status}).", + "unableToLoadSignerWallets": "Impossible de charger les Wallets Signer.", + "loadingSignerWallets": "Chargement des Wallets Signer…", + "onlyAdminsCanEditAuthorities": "Seuls les administrateurs peuvent modifier les autorités Token.", + "deployToken": "Deploy Token", + "deployHelper": "Deploy ce Token Onchain avant les autres opérations de fonds.", + "deployConfirmationTitle": "Deploy Token ?", + "deployConfirmationDescription": "Ceci soumettra la transaction Deploy Onchain.", + "deployNow": "Deploy maintenant", + "copied": "Copié", + "unableToCopy": "Impossible de copier", + "tokenNameRequired": "Le nom du Token est requis.", + "updateToken": "Mettre à jour le Token", + "submittingDeploy": "Soumission de la transaction Deploy...", + "deployFinalized": "Transaction Deploy finalisée.", + "refreshSupply": "Actualiser la Supply", + "mintDetailsRequired": "La destination Mint et le montant sont requis.", + "amountPositive": "Le montant doit être positif.", + "mintConfirmationTitle": "Mint Tokens ?", + "mintConfirmationDescription": "Ceci soumettra une transaction Mint Onchain.", + "mintNow": "Mint maintenant", + "submittingMint": "Soumission de la transaction Mint...", + "mintFinalized": "Transaction Mint finalisée.", + "burnDetailsRequired": "La source Burn et le montant sont requis.", + "burnConfirmationTitle": "Burn Tokens ?", + "burnConfirmationDescription": "Ceci soumettra une transaction Burn Onchain.", + "burnNow": "Burn maintenant", + "submittingBurn": "Soumission de la transaction Burn...", + "burnFinalized": "Transaction Burn finalisée.", + "seizeDetailsRequired": "La source, la destination et le montant Seize sont requis.", + "seizeConfirmationTitle": "Force transfer ?", + "seizeConfirmationDescription": "Ceci soumettra une transaction Seize (Force transfer) Onchain.", + "transferNow": "Transfer maintenant", + "submittingForceTransfer": "Soumission de la transaction Force transfer...", + "forceTransferFinalized": "Transaction Force transfer finalisée.", + "forceBurnDetailsRequired": "La source Force burn et le montant sont requis.", + "forceBurnConfirmationTitle": "Force burn Tokens ?", + "forceBurnConfirmationDescription": "Ceci soumettra une transaction Force burn Onchain.", + "forceBurnNow": "Force burn maintenant", + "submittingForceBurn": "Soumission de la transaction Force burn...", + "forceBurnFinalized": "Transaction Force burn finalisée.", + "updateAuthority": "Mettre à jour l'autorité", + "updateAuthorityLabel": "Mettre à jour {authority}", + "updatingAuthority": "Mise à jour de {authority}...", + "authorityUpdated": "{authority} mise à jour.", + "authorityConfirmationTitle": "Mettre à jour l'autorité ?", + "authorityConfirmationDescription": "Ceci soumettra une transaction de mise à jour d'autorité Onchain.", + "updateNow": "Mettre à jour", + "submittingAuthority": "Soumission de la mise à jour d'autorité...", + "authorityFinalized": "Mise à jour d'autorité finalisée.", + "pauseToken": "Mettre le Token en pause", + "unpauseToken": "Unpause Token", + "pauseConfirmationTitle": "Mettre le Token en pause ?", + "unpauseConfirmationTitle": "Unpause Token ?", + "pauseConfirmationDescription": "Ceci soumettra une transaction de pause Onchain.", + "unpauseConfirmationDescription": "Ceci soumettra une transaction Unpause Onchain.", + "pauseNow": "Mettre en pause", + "unpauseNow": "Unpause maintenant", + "submittingPause": "Soumission de la transaction de pause...", + "submittingUnpause": "Soumission de la transaction Unpause...", + "pauseFinalized": "Transaction de pause finalisée.", + "unpauseFinalized": "Transaction Unpause finalisée.", + "accountAddressRequired": "L'adresse du compte est requise.", + "unfreezeAccount": "Unfreeze compte", + "unfreezeConfirmationTitle": "Unfreeze compte ?", + "unfreezeConfirmationDescription": "Ceci soumettra une transaction Unfreeze Onchain.", + "unfreezeNow": "Unfreeze maintenant", + "submittingUnfreeze": "Soumission de la transaction Unfreeze...", + "unfreezeFinalized": "Transaction Unfreeze finalisée.", + "freezeAccount": "Freeze compte", + "freezeConfirmationTitle": "Freeze compte ?", + "freezeConfirmationDescription": "Ceci soumettra une transaction Freeze Onchain.", + "freezeNow": "Freeze maintenant", + "submittingFreeze": "Soumission de la transaction Freeze...", + "freezeFinalized": "Transaction Freeze finalisée.", + "removeAllowlistEntry": "Supprimer l'entrée Allowlist", + "tokenIdCopied": "ID Token copié", + "loadingAuthorityWalletAccess": "Chargement de l'accès au Wallet d'autorité…", + "loadingComplianceControls": "Chargement des contrôles de conformité…", + "deploySignerHint": "Payez les frais de transaction et de compte depuis le Wallet Signer ou avec le parrainage Kora.", + "deployWithWallet": "Deploy avec Wallet", + "koraUnavailable": "Le parrainage Kora est indisponible.", + "deployWithKora": "Deploy avec Kora", + "destinationNotAllowlisted": "La destination n'est pas dans l'Allowlist de ce Token.", + "destinationDenylisted": "La destination est dans la Denylist de ce Token.", + "actionPaused": "Le Token est en pause. Unpause pour {action}.", + "actionRequiresActive": "Le Token doit être actif pour {action}.", + "actionRevoked": "Le Token est révoqué et ne peut plus {action}.", + "forceTransfer": "Force transfer", + "forceBurn": "Force burn", + "mintingDisabled": "Mint est désactivé pour ce Token.", + "noMintAuthorityConfigured": "Aucune autorité Mint n'est configurée.", + "maximumSupplyReached": "La Supply maximale est atteinte.", + "supplyZero": "La Supply est nulle.", + "noPermanentDelegateAuthority": "L'autorité Permanent Delegate n'est pas configurée.", + "noSupplyHeld": "Aucune Supply n'est actuellement détenue.", + "revokedTokensCannotPause": "Les Token révoqués ne peuvent pas être mis en pause ou Unpause.", + "pauseRequiresActiveToken": "Le Token doit être Deploy et actif avant les contrôles de pause.", + "noPauseAuthorityConfigured": "Aucune autorité de pause n'est configurée. Définissez d'abord une autorité pausable ou Mint.", + "freezingDisabled": "Freeze est désactivé pour ce Token.", + "noFreezeAuthorityConfigured": "Aucune autorité Freeze n'est configurée.", + "unknownError": "Erreur inconnue", + "unknown": "inconnu", + "ok": "ok", + "executionRouteFailed": "Échec de la route d'exécution ({status})", + "actionFailed": "Échec de {action} ({status}) : {error}", + "actionSucceeded": "{action} réussi ({status})", + "requestFailed": "Échec de la demande", + "mintAuthorityHelper": "Peut Mint de nouveaux Tokens.", + "freezeAuthorityHelper": "Peut Freeze et Unfreeze les comptes Token.", + "metadataAuthorityHelper": "Peut mettre à jour les métadonnées Token.", + "permanentDelegateHelper": "Peut effectuer des opérations déléguées de transfert/Burn.", + "noControlledWalletsAvailable": "Aucun Wallet contrôlé ne peut signer cette action.", + "noSignerConfigured": "Aucun Signer n'est configuré pour cette action.", + "requiredSignerNotControlled": "Le Signer requis ne fait pas partie de vos Wallets contrôlés.", + "mintAuthorityNotControlled": "L'autorité Mint ne fait pas partie de vos Wallets contrôlés.", + "permanentDelegateNotControlled": "L'autorité Permanent Delegate ne fait pas partie de vos Wallets contrôlés.", + "authority": "autorité", + "noAuthorityConfigured": "Aucune {authority} n'est configurée.", + "authorityNotControlled": "{authority} ne fait pas partie de vos Wallets contrôlés.", + "freezeAuthorityNotControlled": "L'autorité Freeze ne fait pas partie de vos Wallets contrôlés.", + "pauseAuthorityNotControlled": "L'autorité de pause ne fait pas partie de vos Wallets contrôlés.", + "validMintAmount": "Saisissez un montant Mint valide pour ce Token.", + "mintAmountPositive": "Le montant Mint doit être supérieur à zéro.", + "mintAmountExceedsSupplyCap": "Le montant Mint dépasse le plafond de Supply restant de {amount} {symbol}.", + "validBurnAmount": "Saisissez un montant Burn valide pour ce Token.", + "burnAmountPositive": "Le montant Burn doit être supérieur à zéro.", + "burnAmountExceedsSupply": "Le montant Burn dépasse la Supply actuelle de {amount} {symbol}.", + "standardBurnSignerOnly": "Le Burn standard ne fonctionne que depuis le Wallet Signer sélectionné. Utilisez Force burn pour un autre Wallet.", + "selectedSignerDoesNotHoldToken": "Le Wallet Signer sélectionné ne détient pas ce Token.", + "selectedWalletOnlyShows": "Le Wallet sélectionné affiche seulement {amount} {symbol}.", + "destinationMustDiffer": "La destination doit différer de la source.", + "validTransferAmount": "Saisissez un montant de transfert valide pour ce Token.", + "transferAmountPositive": "Le montant du transfert doit être supérieur à zéro.", + "selectedSourceDoesNotHoldToken": "Le Wallet source sélectionné ne détient pas ce Token.", + "forceBurnAmountPositive": "Le montant Force burn doit être supérieur à zéro.", + "forceBurnAmountExceedsSupply": "Le montant Force burn dépasse la Supply actuelle de {amount} {symbol}.", + "submittingAction": "Soumission de {action}...", + "transactionFinalized": "Transaction finalisée.", + "transactionFailed": "Échec de la transaction.", + "sendTransaction": "Envoyer la transaction ?", + "sendTransactionDescription": "Ceci soumettra une transaction Onchain. Voulez-vous continuer ?", + "goAhead": "Continuer", + "token": "Token" + }, + "forms": { + "saveMetadata": "Enregistrer les métadonnées", + "updateMetadata": "Mettre à jour les métadonnées", + "updateMetadataDescription": "Modifier les métadonnées Token.", + "name": "Nom", + "enterTokenName": "Saisissez un nom de Token.", + "description": "Description", + "uri": "URI", + "imageUrl": "URL de l'image", + "mintDescription": "Mint vers le Wallet ou compte Token de destination.", + "destination": "Destination", + "enterSolanaAddress": "Saisissez une adresse Solana valide.", + "destinationPlaceholder": "Wallet ou compte Token de destination", + "amount": "Montant", + "memo": "Memo", + "burnDescription": "Burn depuis le Wallet ou compte Token source.", + "source": "Source", + "sourcePlaceholder": "Wallet Signer ou son compte Token", + "sourceWalletPlaceholder": "Wallet ou compte Token source", + "forceTransferDescription": "Transfert Seize administratif entre comptes.", + "forceBurnDescription": "Force burn administratif depuis le compte source.", + "mintAuthority": "Autorité Mint", + "freezeAuthority": "Autorité Freeze", + "permanentDelegate": "Permanent Delegate", + "metadataAuthority": "Autorité des métadonnées", + "updateAuthority": "Mettre à jour l'autorité", + "updateAuthorityDescription": "Faites pivoter ou supprimez les autorités Token.", + "role": "Rôle", + "currentAuthorityOptional": "Autorité actuelle (facultatif)", + "newAuthorityEmptyToRemove": "Nouvelle autorité (vide pour supprimer)", + "pauseControls": "Contrôles de pause", + "pauseControlsDescription": "Mettre en pause ou reprendre les transferts du Token.", + "alreadyPaused": "Le Token est déjà en pause.", + "notPaused": "Le Token n'est pas en pause.", + "freezeControls": "Contrôles Freeze", + "freezeControlsDescription": "Freeze ou libérez les avoirs Token d'un Wallet pour ce Mint.", + "walletAddress": "Adresse Wallet", + "enterWalletAddress": "Saisissez l'adresse Wallet. SDP dérivera automatiquement le compte Token associé pour ce Mint.", + "walletAddressPlaceholder": "Adresse Wallet détenant ce Token", + "walletAddressInstruction": "Saisissez l'adresse Wallet détenant ce Token. SDP dérive automatiquement le compte Token associé pour ce Mint.", + "freezeReason": "Motif (Freeze uniquement)", + "controlListDescription": "Gérez les adresses de destination approuvées pour ce Token.", + "address": "Adresse", + "label": "Libellé", + "enterLabel": "Saisissez un libellé ou laissez vide.", + "noLabel": "Sans libellé", + "removeEntry": "Supprimer l'entrée" + }, + "authority": { + "resolvedAutomatically": "Résolu automatiquement depuis l'état du Token", + "closeModal": "Fermer la fenêtre d'autorité", + "save": "Enregistrer l'autorité", + "current": "Autorité actuelle", + "whatThisMeans": "Ce que cela implique", + "confirmNone": "Oui, définir sur Aucun", + "new": "Nouvelle autorité", + "selectWallet": "Sélectionner un Wallet contrôlé", + "custom": "Autorité personnalisée", + "solanaAddress": "Adresse Solana", + "noneWalletWarning": "Choisir Aucun effacera cette autorité. Vous confirmerez avant soumission.", + "noneDescription": "Cette autorité sera effacée si vous enregistrez cette modification.", + "controlledWalletHint": "Les Wallets contrôlés sont les cibles d'autorité recommandées.", + "useCustom": "Utiliser une adresse personnalisée", + "chooseWallet": "Choisir un Wallet contrôlé", + "solanaAddressOrNone": "Adresse Solana ou laissez vide pour définir Aucun", + "enterAddressOrNone": "Saisissez une adresse Solana valide ou laissez vide pour définir l'autorité sur Aucun.", + "noWalletsHint": "Aucun Wallet contrôlé disponible. Saisissez une adresse ou laissez vide pour définir l'autorité sur Aucun.", + "noneFieldWarning": "Définir ce champ sur Aucun effacera l'autorité. Vous confirmerez avant soumission.", + "mintNoneTitle": "Définir l'autorité Mint sur Aucun ?", + "mintNoneDescription": "Ceci effacera l'autorité Mint du Token.", + "mintNoneImpact": "Aucun Wallet ne pourra Mint de Supply supplémentaire après cette modification.", + "freezeNoneTitle": "Définir l'autorité Freeze sur Aucun ?", + "freezeNoneDescription": "Ceci effacera l'autorité Freeze du Token.", + "freezeNoneImpact": "Les comptes Token ne pourront plus être Freeze ou Unfreeze après cette modification.", + "delegateNoneTitle": "Définir l'autorité Permanent Delegate sur Aucun ?", + "delegateNoneDescription": "Ceci effacera l'autorité Permanent Delegate du Token.", + "delegateNoneImpact": "Les actions administratives de transfert délégué et Burn ne seront plus disponibles après cette modification.", + "metadataNoneTitle": "Définir l'autorité des métadonnées sur Aucun ?", + "metadataNoneDescription": "Ceci effacera l'autorité des métadonnées du Token.", + "metadataNoneImpact": "Les mises à jour de métadonnées ne seront plus disponibles via cette autorité après cette modification." + }, + "wizard": { + "stepOf": "Étape {current} sur {total}", + "creatingDraft": "Création du Draft Asset…", + "draftCreated": "Draft Asset créé.", + "failedToCreate": "Échec de création du Draft.", + "creating": "Création…", + "reviewAndFinish": "Vérifier et terminer", + "reviewDescription": "Vérifiez tous les détails ci-dessous. Vous pouvez modifier chaque section avant de créer votre Draft." + }, + "confirmDraft": { + "ariaLabel": "Créer le Draft Asset", + "title": "Créer ce Draft Asset ?", + "descriptionStart": "Ceci crée un Draft", + "of": "de", + "descriptionEnd": ". Vous pouvez continuer à le modifier et le publier lorsque vous êtes prêt." + }, + "summary": { + "title": "Résumé", + "assetCategory": "Catégorie d'Asset", + "assetType": "Type d'Asset", + "peggedTo": "Indexé sur", + "accessControl": "Contrôle d'accès", + "transferRestrictions": "Restrictions de transfert", + "investorReporting": "Reporting investisseurs", + "enabled": "Activé", + "lastUpdated": "Dernière mise à jour", + "resolveBeforeCreating": "À résoudre avant création", + "readyToCreate": "Vous pouvez créer un Draft", + "readyDescription": "Vous pouvez vérifier, modifier et publier lorsque vous êtes prêt.", + "privateByDefault": "Privé par défaut", + "privateDescription": "Les détails fournis sont privés et servent uniquement à configurer votre Asset." + }, + "classificationRail": { + "title": "Fonctionnement", + "assetProfile": "Profil Asset", + "assetProfileDescription": "Vous sélectionnez la catégorie et le type. SDP stocke vos métadonnées d'émission canoniques.", + "issuanceMetadata": "Métadonnées d'émission", + "issuanceMetadataDescription": "Inclut les champs Asset, conformité, chaîne et personnalisés (client/intégration).", + "publicProjection": "Projection publique", + "publicProjectionDescription": "SDP projette un sous-ensemble public sûr vers les métadonnées Token.", + "tokenMetadataUri": "URI des métadonnées Token", + "tokenMetadataUriDescription": "SDP héberge l'URI par défaut qui renvoie uniquement les métadonnées publiques.", + "privateDescription": "Les métadonnées de conformité et personnalisées restent privées sauf inclusion explicite dans la projection publique." + }, + "assetProfileForm": { + "fixHighlightedFields": "Corrigez les champs en surbrillance avant d'enregistrer." + }, + "templates": { + "stablecoinName": "Stablecoin", + "stablecoinDescription": "Stablecoin adossés à l'USD avec contrôles de conformité.", + "stablecoinHelper": "Idéal pour Assets fiat-pegged avec contrôles de transfert et Freeze admin.", + "tokenizedSecurityName": "Tokenized Security", + "tokenizedSecurityDescription": "Assets réglementés avec Allowlist par défaut.", + "tokenizedSecurityHelper": "Conçu pour les instruments réglementés exigeant des contrôles des participants.", + "customName": "Personnalisé", + "customDescription": "Configuration Token-2022 entièrement personnalisable.", + "customHelper": "Commencez par un profil vide et ajustez les paramètres d'émission aux exigences avancées." + }, + "overview": { + "title": "Aperçu du Token", + "tokenAddress": "Adresse Token", + "mintAuthority": "Autorité Mint", + "supply": "Supply", + "template": "Template", + "totalSupply": "Supply totale", + "readyForDeploy": "Prêt pour Deploy", + "readyForDeployDescription": "Cet Asset est prêt pour Deploy — continuez dans l'onglet Opérations.", + "mintAddress": "Adresse Mint", + "notDeployedYet": "Pas encore Deploy", + "noDescription": "Aucune description — ajoutez-en une dans l'onglet Détails." + }, + "operations": { + "deployHelper": "Deploy ce Token Onchain avant les autres opérations de fonds." + }, + "taxonomy": { + "stablecoin": "Stablecoin", + "stablecoinDescription": "Assets conçus pour maintenir une valeur stable, généralement adossés à des monnaies fiat ou autres Assets liquides.", + "fiatBacked": "Adossé à une monnaie fiat", + "fiatBackedDescription": "Adossé à 1:1 à des réserves de monnaie fiat détenues dans des institutions financières réglementées.", + "cryptoBacked": "Adossé aux crypto-actifs", + "cryptoBackedDescription": "Garanti par des crypto-actifs sous garde pour maintenir la parité.", + "tokenizedSecurity": "Tokenized Security", + "tokenizedSecurityDescription": "Instruments financiers réglementés ou représentations numériques de titres.", + "equity": "Actions", + "equityDescription": "Actions Tokenized ou intérêts assimilés dans une entreprise.", + "debt": "Dette / Obligation", + "debtDescription": "Obligations, billets ou autres instruments de dette.", + "fund": "Fonds / ETF", + "fundDescription": "Parts de fonds ou actions de fonds négociés en bourse.", + "generic": "Asset numérique hors titre", + "genericDescription": "Autres Assets Tokenized ne relevant pas des catégories ci-dessus.", + "commodities": "Matières premières", + "commoditiesDescription": "Créances sur des matières premières physiques ou ressources naturelles.", + "realEstate": "Immobilier", + "realEstateDescription": "Intérêts immobiliers ou biens Tokenized.", + "collectibles": "Objets de collection", + "collectiblesDescription": "Assets de collection uniques ou en édition limitée." + }, + "config": { + "advanced": "Avancé", + "advancedCapacitiesDescription": "Les capacités recommandées sont présélectionnées selon le profil Asset.", + "usd": "USD", + "eur": "EUR", + "gbp": "GBP", + "jpy": "JPY", + "sgd": "SGD", + "unitedStates": "États-Unis", + "europeanUnion": "Union européenne", + "unitedKingdom": "Royaume-Uni", + "singapore": "Singapour", + "other": "Autre", + "regD": "Reg D", + "regS": "Reg S", + "regA": "Reg A+", + "publicOffering": "Offre publique", + "commodityBacked": "Adossé à une matière première", + "algorithmic": "Algorithmique", + "financialDetails": "Détails financiers", + "financialDetailsDescription": "Attributs financiers clés de l'Asset.", + "issuerName": "Nom de l'émetteur", + "issuerNamePlaceholder": "ex. Acme Financial Inc.", + "backingType": "Type de garantie", + "currency": "Devise", + "selectField": "Sélectionner {field}", + "searchCurrencies": "Rechercher des devises", + "pegTarget": "Parité ou cible", + "pegTargetPlaceholder": "1,00 USD", + "reserveAsset": "Asset de réserve", + "reserveAssetPlaceholder": "USD (dollar américain)", + "reserveCustodian": "Conservateur de réserve", + "reserveCustodianPlaceholder": "ex. Acme Treasury Ltd.", + "redemption": "Rachat", + "redemptionHelp": "Les détenteurs peuvent échanger les Tokens contre les réserves sous-jacentes.", + "securityDetails": "Détails du titre", + "securityDetailsDescription": "Informations sur l'émetteur et l'offre.", + "jurisdiction": "Juridiction", + "offeringType": "Type d'offre", + "categoryAssetDetails": "Détails de l'Asset", + "categoryAssetDetailsDescription": "Ce qui sous-tend ou représente cet Asset.", + "underlyingAsset": "Asset sous-jacent", + "underlyingAssetPlaceholder": "ex. Or, immobilier", + "custodian": "Conservateur", + "custodianPlaceholder": "ex. Acme Custody", + "allowList": "Liste autorisée", + "blockList": "Liste bloquée", + "kyc": "KYC", + "kycDescription": "Exige une vérification d'identité avant la détention ou le transfert de Tokens.", + "restrictTradingHours": "Restreindre les heures de négociation", + "restrictTradingHoursDescription": "Limitez les transferts Token à certains jours et créneaux horaires.", + "freezeTransfers": "Freeze les transferts", + "freezeTransfersDescription": "Freeze les Tokens en réponse à des événements de conformité ou enquêtes.", + "issueRetireControls": "Contrôles d'émission et retrait", + "issueRetireControlsDescription": "Contrôlez qui peut émettre de nouveaux Tokens ou retirer la Supply existante.", + "redemptionApprovals": "Approbations de rachat", + "redemptionApprovalsDescription": "Exige une approbation avant de racheter des Tokens contre les réserves sous-jacentes.", + "investorReporting": "Reporting investisseurs", + "investorReportingDescription": "Générez des rapports périodiques pour les investisseurs et parties prenantes.", + "transferApprovals": "Approbations de transfert", + "transferApprovalsDescription": "Exige une approbation pour les transferts au-delà d'un seuil défini." + }, + "playground": { + "tokenNameExample": "Acme Dollar", + "tokenSymbolExample": "ACME", + "selectTemplate": "Sélectionner un Template", + "settlementAssetExample": "Asset de règlement adossé à l'USD", + "metadataUriExample": "https://example.com/metadata/acme-usd.json", + "optionalHostedUri": "uri (facultatif — SDP héberge si omis)", + "updatedTokenName": "Nom du Token mis à jour", + "updatedTokenDescription": "Description du Token mise à jour", + "updatedMetadataUri": "https://example.com/updated-metadata.json", + "tokenImageUrl": "https://example.com/token.png", + "selectStatus": "Sélectionner un statut", + "active": "Actif", + "paused": "En pause", + "productName": "Émission", + "none": "Aucun", + "low": "Faible", + "medium": "Moyen", + "high": "Élevé", + "true": "Vrai", + "false": "Faux", + "selectPriorityFee": "Sélectionner options priorityFee", + "selectSimulate": "Sélectionner options simulate", + "amountPlaceholder": "ex. 1000", + "listTemplates": "Lister les Templates", + "getTemplate": "Obtenir le Template", + "createToken": "Créer un Token", + "listTokens": "Lister les Tokens", + "getToken": "Obtenir le Token", + "updateToken": "Mettre à jour le Token", + "listTokenTransactions": "Lister les transactions Token", + "refreshTotalSupply": "Actualiser la Supply totale", + "deployToken": "Deploy Token", + "mintTokens": "Mint Tokens", + "burnTokens": "Burn Tokens", + "seizeTokens": "Seize Tokens", + "forceBurn": "Force Burn", + "updateAuthority": "Mettre à jour l'autorité", + "pauseToken": "Mettre le Token en pause", + "unpauseToken": "Unpause Token", + "freezeAccount": "Freeze compte", + "unfreezeAccount": "Unfreeze compte", + "listFrozenAccounts": "Lister les comptes Freeze", + "listAllowlist": "Lister l'Allowlist", + "addAllowlistEntry": "Ajouter une entrée Allowlist", + "removeAllowlistEntry": "Supprimer une entrée Allowlist", + "tokenIdPlaceholder": "ID Token (ex. tok_abc123)", + "templateIdPlaceholder": "ID Template (ex. stablecoin)", + "authorityRoleMint": "Mint", + "authorityRoleFreeze": "Freeze", + "authorityRolePermanentDelegate": "Permanent Delegate", + "authorityRoleMetadata": "Métadonnées", + "solanaAddressPlaceholder": "Adresse Solana (32-44 caractères)", + "optionalMemo": "Memo facultatif", + "tokenAccountAddressPlaceholder": "Adresse de compte Token (32-44 caractères)", + "sourceTokenAccountAddress": "Adresse du compte Token source", + "destinationTokenAccountAddress": "Adresse du compte Token de destination", + "delegateAuthorityAddress": "Adresse de l'autorité Delegate", + "tokenAccountAddress": "Adresse de compte Token", + "selectAuthorityRole": "Sélectionner un rôle d'autorité", + "currentAuthorityAddress": "Adresse de l'autorité actuelle", + "newAuthorityAddress": "Adresse de la nouvelle autorité", + "walletAddressToFreeze": "Adresse Wallet à Freeze", + "optionalFreezeReason": "Motif Freeze facultatif", + "walletAddressToUnfreeze": "Adresse Wallet à Unfreeze", + "treasuryExample": "Trésorerie", + "addressToAllowlist": "Adresse à ajouter à l'Allowlist", + "optionalLabel": "Libellé facultatif", + "allowlistEntryIdPlaceholder": "ID d'entrée Allowlist (ex. allow_123)" + }, + "compliance": { + "forceTransfer": "Force transfer", + "forceBurn": "Force burn", + "freeze": "Freeze", + "pause": "Pause", + "accessPolicy": "Politique d'accès", + "accessPolicyDescription": "Documente la politique d'accès prévue pour cet Asset.", + "accessControl": "Contrôle d'accès", + "notSet": "Non défini", + "lockReason": "Verrouillé après Deploy — l'application Onchain ne peut pas être modifiée.", + "selectAccessControl": "Sélectionner un contrôle d'accès", + "appliedOnDeploy": "Appliqué Onchain lors du Deploy du Token.", + "controls": "Contrôles de conformité", + "controlsDescription": "Actions Onchain pour ce Token — elles prennent effet immédiatement." + }, + "classification": { + "title": "Quel est cet Asset ?", + "description": "Commencez par nous indiquer ce que représente cet Asset et sa classification.", + "name": "Nom", + "namePlaceholder": "ex. USD Workshop Money Market Fund", + "nameHint": "Un nom clair pour identifier cet Asset.", + "chooseClassification": "Choisir une classification", + "notSure": "Je ne sais pas quoi choisir", + "chooseAssetType": "Choisir un type d'Asset" + }, + "review": { + "assetTitle": "Asset", + "assetDescription": "L'Asset et sa représentation.", + "assetCategory": "Catégorie d'Asset", + "assetType": "Type d'Asset", + "name": "Nom", + "symbol": "Symbole", + "assetDetailsTitle": "Détails de l'Asset", + "assetDetailsDescription": "Informations clés sur l'Asset.", + "description": "Description", + "issuerName": "Nom de l'émetteur", + "decimals": "Decimals", + "website": "Site web", + "complianceAccessTitle": "Conformité et accès", + "complianceAccessDescription": "Contrôle de l'Asset et utilisateurs autorisés à interagir.", + "accessControl": "Contrôle d'accès", + "allowlist": "Liste autorisée", + "blocklist": "Liste bloquée", + "none": "Aucun", + "allowlistHint": "Seules les adresses approuvées peuvent détenir ou transférer.", + "blocklistHint": "Les adresses bloquées ne peuvent détenir ou transférer.", + "transferRestrictions": "Restrictions de transfert", + "enabled": "Activé", + "disabled": "Désactivé", + "transferRestrictionsHint": "Transferts limités aux participants approuvés.", + "investorReporting": "Reporting investisseurs", + "investorReportingHint": "Rapports d'activité disponibles pour investisseurs et parties prenantes.", + "publicInformationTitle": "Informations publiques", + "publicInformationDescription": "Les informations sûres visibles par tous.", + "publicName": "Nom public", + "publicSymbol": "Symbole public", + "logo": "Logo", + "publicDescription": "Description (publique)", + "edit": "Modifier", + "notProvided": "—" + }, + "publicInfo": { + "name": "Nom", + "symbol": "Symbole", + "description": "Description", + "decimals": "Decimals", + "category": "Catégorie", + "assetType": "Type d'Asset", + "logo": "Logo", + "untitledAsset": "Asset sans titre", + "notProvided": "—", + "publicTokenInformation": "Informations publiques du Token", + "publicTokenInfoHelp": "Voici comment votre Asset apparaîtra dans les Wallets, Explorers et au public.", + "includedInPublicView": "Inclus dans la vue publique", + "publicCount": "{count} publics", + "publicCoverage": "{publicCount} champs publics sur {totalCount}", + "notIncludedByDefault": "Non inclus par défaut", + "notIncludedHelp": "Ces champs restent privés sauf si vous choisissez de les inclure.", + "preview": "Aperçu", + "token": "Token", + "explorer": "Explorer", + "wallet": "Wallet", + "assetLogo": "Logo {name}", + "asset": "Asset", + "mintAddress": "Adresse Mint", + "copyMintAddress": "Copier l'adresse Mint", + "viewOnExplorer": "Voir dans Explorer", + "copied": "Copié", + "noPublicDescription": "Aucune description publique", + "decimalsValue": "{count} Decimals", + "alwaysPublic": "Toujours public — ne peut être masqué", + "hidePublicField": "Public — masquer ce champ", + "showPublicField": "Masqué — afficher ce champ publiquement" + }, + "assetDetails": { + "title": "Détails de l'Asset", + "description": "Ajoutez les informations clés sur cet Asset. Vous pouvez les modifier à tout moment.", + "tabs": { + "overview": "Aperçu", + "compliance": "Conformité et accès", + "operational": "Opérationnel", + "custom": "Champs personnalisés" + }, + "about": "À propos de cet Asset", + "namePlaceholder": "ex. Verde Dollar", + "lockedAfterCreation": "Verrouillé après création", + "aboutDescription": "Informations de base décrivant cet Asset.", + "symbolPlaceholder": "ex. vUSD", + "descriptionLabel": "Description", + "descriptionPlaceholder": "Décrivez ce que représente cet Asset.", + "website": "Site web", + "websitePlaceholder": "https://…", + "logoImageUrl": "URL de l'image du logo", + "logoPlaceholder": "https://…/logo.png", + "logoHint": "Affiché à côté de votre Token dans les Wallets et Explorers.", + "documents": "Documents et références", + "documentsDescription": "Documents et références importants liés à cet Asset.", + "accessControlDescription": "Choisissez comment ce Token traite les adresses de destination approuvées ou bloquées.", + "learnLists": "Découvrez la différence entre listes autorisées et bloquées", + "operational": "Opérationnel", + "operationalDescription": "Paramètres opérationnels facultatifs.", + "signingWallet": "Wallet de signature", + "optionalSignerHint": "Facultatif — ne sélectionnez rien pour utiliser le Signer par défaut du projet.", + "customFields": "Champs personnalisés", + "customFieldsDescription": "Ajoutez vos champs privés, stockés sous custom.customer.", + "projectDefaultSigner": "Signer par défaut du projet", + "signingWalletLockReason": "Défini à la création — les opérations peuvent utiliser un autre Signer.", + "documentTypePlaceholder": "Type de document", + "documentNamePlaceholder": "Nom", + "removeDocument": "Supprimer le document", + "addDocument": "Ajouter un document", + "hideJson": "Masquer JSON", + "viewJson": "Voir JSON", + "copied": "Copié !", + "customFieldKey": "Clé", + "customFieldValue": "Valeur", + "removeCustomField": "Supprimer le champ", + "addCustomField": "Ajouter un champ", + "copyJson": "Copier JSON" + }, + "assetProfileDetails": { + "privateByDefault": "Ces informations sont privées par défaut et ne seront pas visibles au public, sauf si vous choisissez de les inclure." + } + } +} diff --git a/apps/sdp-web/messages/fr/dashboard-payments.json b/apps/sdp-web/messages/fr/dashboard-payments.json new file mode 100644 index 000000000..3f40f9482 --- /dev/null +++ b/apps/sdp-web/messages/fr/dashboard-payments.json @@ -0,0 +1,910 @@ +{ + "DashboardPayments": { + "page": { + "unavailableStatus": "indisponible", + "unknownError": "Erreur inconnue", + "walletApiError": "Wallet API {status} : {error}", + "walletAggregateApiError": "Wallet agrégat API {status} : {error}", + "transferApiError": "Transfer API {status} : {error}" + }, + "workspace": { + "walletListRequestFailed": "Échec de la demande de liste Wallet ({status}).", + "walletAggregateRequestFailed": "Échec de la demande d'agrégation Wallet ({status}).", + "walletAggregateMissing": "La réponse globale Wallet ne contient pas de détails globaux.", + "walletPolicyRequestFailed": "Échec de la demande de stratégie Wallet ({status}).", + "transferListRequestFailed": "Échec de la demande de liste Transfer ({status}).", + "transferListMissing": "La réponse de la liste Transfer ne contient pas de données Transfer.", + "transferLookupFailed": "La recherche Transfer a échoué ({status}).", + "transferLookupMissing": "La réponse de recherche Transfer ne contient pas de données Transfer.", + "transferLookupMultiple": "La recherche Transfer a renvoyé plusieurs Transfers.", + "transferCancellationFailed": "Échec de l'annulation de Transfer ({status}).", + "rampEstimateRequestFailed": "Échec de la demande d'estimation Ramp ({status}).", + "rampEstimateMissing": "La réponse d'estimation Ramp ne contient pas d'estimations.", + "walletBalancesRequestFailed": "Échec de la demande de soldes Wallet ({status}).", + "walletBalancesMissing": "La réponse aux soldes Wallet ne contient pas de détails sur le solde.", + "walletPolicyUpdateFailed": "Échec de la mise à jour de la stratégie Wallet ({status}).", + "walletPolicyUpdateEmpty": "La mise à jour de la stratégie Wallet a renvoyé une réponse vide.", + "transferRequestFailed": "La requête Transfer a échoué ({status}).", + "transferMissing": "La réponse Transfer ne contient pas de détails sur Transfer.", + "recipientListRequestFailed": "La demande de liste de destinataires a échoué ({status}).", + "recipientListMissing": "La réponse de la liste des destinataires ne contient pas de destinataires.", + "batchEstimateRequestFailed": "Échec de la demande d'estimation Batch ({status}).", + "batchEstimateMissing": "La réponse d'estimation Batch ne contient pas de détails d'estimation.", + "batchTransferRequestFailed": "La requête Batch Transfer a échoué ({status}).", + "batchTransferMissing": "La réponse Batch Transfer ne contient pas de détails sur Batch.", + "rampEventRequestFailed": "La demande d'événement {provider} a échoué ({status}).", + "rampEventMissing": "La réponse à l'événement {provider} ne contient pas les détails de Transfer.", + "counterpartyAccountsRequestFailed": "Échec du chargement des comptes ({status}).", + "sandboxSimulationRequestFailed": "La simulation Sandbox a échoué ({status}).", + "requirementsRequestFailed": "Échec de la demande d'exigences ({status}).", + "requirementsAdvanceFailed": "Échec de l'avancement des exigences ({status}).", + "requirementsContextMissing": "Impossible de faire progresser les exigences sans provider et Counterparty.", + "complianceCheckFailed": "Le contrôle de conformité a échoué.", + "destinationRequired": "L'adresse de destination est requise.", + "transferBlocked": "Transfer bloqué.", + "transferBlockedDescription": "Exécutez un contrôle de conformité ou utilisez une destination déjà présente dans la source Wallet Allowlist.", + "transactionSent": "Transaction envoyée.", + "viewOnSolanaExplorer": "Afficher sur Solana Explorer", + "walletsLoadFailed": "Échec du chargement de Wallets.", + "walletPolicyLoadFailed": "Échec du chargement de la stratégie Wallet.", + "addressRequired": "L'adresse est requise.", + "complianceCheckRequired": "Exécutez un contrôle de conformité avant d’ajouter l’adresse.", + "addressAlreadyAllowlisted": "L'adresse est déjà dans la destination Allowlist.", + "addressAddedToAllowlist": "Adresse ajoutée à la destination Wallet Allowlist.", + "destinationAddressAddFailed": "Échec de l'ajout de l'adresse de destination.", + "sourceWalletRequired": "Sélectionnez d'abord une source Wallet.", + "destinationAllowlistLoadFailed": "Échec du chargement de la destination Allowlist." + }, + "paymentMethods": { + "onchainTransfer": "Transfer Onchain", + "onchainTransferDescription": "Envoyez du crypto depuis un SDP Wallet vers l'adresse Solana d'un Counterparty.", + "payWithFiat": "Payer en fiat", + "payWithFiatDescription": "Convertissez la crypto en fiat et payez via un provider.", + "onchainDeposit": "Dépôt Onchain", + "onchainDepositDescription": "Recevez du crypto directement à une adresse SDP Wallet.", + "depositWithFiat": "Déposer en fiat", + "depositWithFiatDescription": "Achetez de la crypto avec fiat via un provider et déposez-la dans un Wallet." + }, + "cancelTransaction": { + "ariaLabel": "Annuler la transaction", + "title": "Annuler cette transaction ?", + "description": "Cette transaction a déjà été lancée. Si vous annulez maintenant, vous quitterez le flux.", + "keepGoing": "Continuer", + "cancel": "Annuler la transaction" + }, + "sendMode": { + "single": "Unique", + "batch": "Batch", + "onchain": "Onchain" + }, + "ramps": { + "max": "MAX", + "recentTransfersRequestFailed": "La demande de Transfer récente a échoué.", + "recentTransfers": "Transfers récents", + "noRecentTransactions": "Aucune transaction récente.", + "chooseProvider": "Choisir un provider", + "unavailableCount": "{count} indisponible", + "noProvidersAvailable": "Aucun provider n'est disponible pour cette sélection.", + "unavailableProviders": "providers indisponibles", + "walletAddressQrCode": "Code QR d’adresse du Wallet", + "walletReceiveDescription": "Scannez ce code QR ou copiez l'adresse pour recevoir USDC ou n'importe quel SPL Token sur Solana dans le Wallet sélectionné.", + "addressCopied": "Adresse copiée.", + "copyAddress": "Copier l'adresse", + "convertTo": "Convertir en", + "currency": "Devise", + "selectCurrency": "Sélectionnez une devise", + "searchCurrencies": "Rechercher des devises", + "searchAssets": "Rechercher des Assets", + "balanceAvailable": "{amount} disponible", + "amount": "Montant", + "destinationWallet": "Wallet destination", + "sourceWallet": "Wallet source", + "detailsStep": "Détails", + "onrampDepositStep": "Dépôt", + "onrampDepositTitle": "Combien souhaitez-vous déposer ?", + "onrampProviderTitle": "Complétez votre dépôt", + "onrampRequirementsTitle": "Quelques détails pour continuer", + "offrampWalletStep": "Wallet", + "offrampWalletTitle": "De quel Wallet vous retirez-vous ?", + "offrampWithdrawStep": "Se retirer", + "offrampWithdrawTitle": "Combien souhaiteriez-vous retirer ?", + "offrampCompleteStep": "Terminé", + "offrampCompleteTitle": "Complétez votre paiement", + "payoutDetailsStep": "Détails du paiement", + "payoutDetailsTitle": "Où devons-nous envoyer le paiement ?", + "selectDestinationWallet": "Sélectionner un Wallet destination", + "selectSourceWallet": "Sélectionner un Wallet source", + "searchWallets": "Rechercher Wallets", + "fees": "Honoraires {providerFee} {providerCurrency} + {networkFee} {networkCurrency}", + "noFees": "Pas de frais", + "fee": "Frais {amount} {currency}", + "estimatedReceived": "Est. reçu", + "rateKnownAtQuote": "Taux connu à Quote", + "unavailable": "Indisponible", + "acceptTerms": "Accepter les conditions", + "completeVerification": "Vérification complète", + "tryAgain": "Réessayez", + "quoteMissingInstructions": "Il manque des instructions de paiement à Ramp Quote.", + "sendCrypto": "Envoyer {amount} {token}", + "quoteExpired": "Quote expiré", + "sending": "Envoi...", + "transferSubmitted": "Transfer soumis", + "transferFailed": "Échec de Transfer.", + "transactionSentSuccessfully": "Transaction envoyée avec succès.", + "transferStatus": "Statut : {status}", + "submittingOnchainTransfer": "Soumission en chaîne de Transfer.", + "simulatingQuoteFunding": "Simulation du financement Quote.", + "quoteFundingSimulated": "Financement Quote simulé.", + "quoteSimulationFailed": "La simulation Quote a échoué.", + "sandboxSimulationFailed": "La simulation Sandbox a échoué.", + "muralSandboxCurrencyUnsupported": "Le paiement Mural sandbox ne prend pas en charge {currency}.", + "transferSignatureMissing": "Transfer n'a pas renvoyé de signature (statut : {status}).", + "offrampManualDescription": "Envoyez {amount} {token} à l'adresse de dépôt ci-dessous avant l'expiration du Quote. Le provider le convertit au taux verrouillé et le verse automatiquement sur le compte bancaire enregistré.", + "noPayoutProviders": "Aucun provider de paiement n'est activé pour cette organisation.", + "providerPayout": "Paiement {provider}", + "noDepositProviders": "Aucun provider de dépôt n'est activé pour cette organisation.", + "providerDeposit": "Dépôt {provider}", + "quoteRequestFailedStatus": "La requête Ramp Quote a échoué ({status}).", + "quoteResponseMissingDetails": "La réponse Ramp Quote ne contient pas de détails sur Quote.", + "creatingQuote": "Création de Quote.", + "widgetReady": "Widget prêt.", + "quoteReady": "Quote prêt.", + "unableToCreateQuote": "Impossible de créer Quote.", + "quoteRequestFailed": "La requête Ramp Quote a échoué.", + "settingUpAccount": "Configuration de votre compte.", + "moreDetailsNeeded": "Nous avons besoin de quelques détails supplémentaires avant de continuer.", + "unableToStartOnboarding": "Impossible de commencer l'intégration.", + "requirementsRequestFailed": "La demande d'exigences a échoué.", + "nextStepSoon": "Prochaine étape à venir.", + "cannotCancelWithoutQuote": "Impossible d'annuler sans un Quote actif.", + "cancelingTransaction": "Annulation de la transaction.", + "transactionCanceled": "Transaction annulée.", + "unableToCancelTransaction": "Impossible d'annuler la transaction.", + "cancellationFailed": "L'annulation a échoué.", + "funded": "Financé", + "sent": "Envoyé", + "provider": "provider", + "finalFundedAmount": "Montant final financé", + "finalSentAmount": "Montant final envoyé", + "finalReceivedAmount": "Montant final reçu", + "finalPayoutAmount": "Montant du paiement final", + "completed": "Terminé", + "transferId": "Identifiant Transfer", + "quoteId": "Identifiant Quote", + "depositComplete": "Dépôt terminé", + "payoutComplete": "Paiement terminé", + "depositCompleteDescription": "Les fonds ont été réglés à la destination Wallet.", + "payoutCompleteDescription": "Le paiement a été réglé sur le compte bancaire du destinataire.", + "fundedWith": "financé avec", + "from": "de", + "newPayeeHint": "Créez un nouveau bénéficiaire s'il ne figure pas encore dans la liste.", + "newBuyerHint": "Créez un nouvel acheteur s'il n'est pas encore dans la liste.", + "destinationAccount": "Compte de destination", + "selectCounterpartyFirst": "Sélectionnez d'abord un Counterparty", + "noSolanaAccounts": "Aucun compte Solana enregistré", + "selectDestinationAccount": "Sélectionnez un compte de destination", + "searchAccounts": "Rechercher des comptes", + "assetBreakdown": "Panne Asset", + "total": "{amount} total", + "selectCounterparty": "Sélectionnez un Counterparty", + "searchCounterparties": "Rechercher des contreparties", + "counterpartiesLoadFailed": "Échec du chargement des contreparties.", + "openFullScreen": "Ouvrir en plein écran", + "selectField": "Sélectionnez {field}", + "search": "Rechercher…", + "stripeLoadError": "Impossible de charger le paiement Stripe", + "stripeLoadHelp": "La caisse Stripe n'a pas pu être chargée. Vérifiez votre connexion et réessayez.", + "moneygramEventFailed": "Échec de l'enregistrement de l'événement MoneyGram.", + "eventRequestFailed": "La demande d'événement a échoué.", + "moneygramCompletionBeforeTransfer": "MoneyGram a signalé l'achèvement avant que le crypto Transfer ne soit enregistré.", + "moneygramWidgetLoadFailed": "Échec du chargement du widget MoneyGram.", + "unsupportedMoneygramTransaction": "Transaction non prise en charge : {asset} sur {chain}.", + "sourceWalletNoUsdc": "La source Wallet n'a pas de solde USDC à envoyer.", + "coinbaseEventFailed": "Échec de l'enregistrement de l'événement Coinbase.", + "coinbaseOnramp": "Coinbase onramp", + "status": { + "waitingForFunding": "En attente de financement", + "waitingToSend": "En attente d'envoi", + "waitingForFundingDescription": "Envoyez les fonds en suivant les instructions ci-dessus. Nous mettrons à jour ce dépôt automatiquement une fois que le provider aura reçu le paiement.", + "waitingToSendDescription": "Effectuez le paiement en suivant les instructions ci-dessus. Nous mettrons à jour ce Transfer sortant automatiquement une fois que le provider aura reçu votre crypto.", + "depositReceived": "Dépôt reçu", + "sendingPayout": "Envoi du paiement", + "depositReceivedDescription": "Le provider a reçu des fonds et règle le dépôt à la destination Wallet.", + "sendingPayoutDescription": "Le provider a reçu votre crypto et règle le paiement sortant au destinataire.", + "transferComplete": "Transfer terminé", + "payoutSent": "Paiement envoyé", + "transferCompleteDescription": "Le dépôt est terminé. Vous pouvez consulter le Transfer à partir de l'enregistrement Counterparty.", + "payoutSentDescription": "Le paiement sortant a été réglé. Vous pouvez consulter ce Transfer à partir de l'enregistrement Counterparty.", + "transferFailed": "Échec de Transfer", + "payoutFailed": "Le paiement a échoué", + "transferFailedDescription": "Le provider a signalé que ce dépôt avait échoué. Consultez l'enregistrement Counterparty pour connaître le dernier état de Transfer.", + "payoutFailedDescription": "Le provider a signalé que ce paiement sortant avait échoué. Consultez l'enregistrement Counterparty pour connaître le dernier état de Transfer.", + "quoteExpired": "Quote expiré", + "quoteExpiredFundingDescription": "Ce Quote a expiré avant la fin du Transfer. Créez un nouveau Quote pour continuer le financement.", + "quoteExpiredPayoutDescription": "Ce Quote a expiré avant la fin du paiement. Créez un nouveau Quote pour poursuivre le retrait.", + "updated": "Statut Transfer mis à jour", + "currentProviderStatus": "Statut actuel du provider : {status}.", + "preparing": "Préparation du statut Transfer", + "preparingDescription": "Nous attendons le record Transfer lié à ce Quote." + } + }, + "onchainSend": { + "noAssets": "Ce Wallet n'a aucun élément disponible à envoyer.", + "addSolanaAddress": "Ajouter l'adresse Solana", + "counterpartyNoAddress": "{counterparty} n’a pas encore d’adresse Solana enregistrée.", + "thisCounterparty": "Ce Counterparty", + "attachDestination": "Joignez une autre adresse de destination pour ce Counterparty.", + "sourceWallet": "Source Wallet", + "selectSourceWallet": "Sélectionnez une source Wallet", + "searchWallets": "Rechercher Wallets", + "amount": "Montant", + "asset": "Asset", + "selectAsset": "Sélectionnez un Asset", + "memoOptional": "Memo (facultatif)", + "memoPlaceholder": "Ajouter une note pour ce Transfer", + "to": "À", + "destination": "Destination", + "destinationTitle": "Où doivent aller les fonds ?", + "details": "Détails", + "detailsTitle": "Que souhaiteriez-vous envoyer ?", + "review": "Examen", + "reviewTitle": "Avis Transfer", + "submittingTransfer": "Soumission de Transfer.", + "memo": "Memo", + "counterparty": "Counterparty", + "toCounterparty": "à {counterparty}", + "transferSubmitted": "Transfer soumis", + "transactionSent": "Transaction envoyée avec succès.", + "transferFailed": "Échec de Transfer.", + "transferSuccess": "Votre Transfer a été envoyé avec succès.", + "transferStatus": "Statut : {status}", + "viewOnExplorer": "Afficher sur l'explorateur" + }, + "onchainReceive": { + "wallet": "Wallet", + "walletTitle": "Quel Wallet devrait recevoir des fonds ?", + "receive": "Recevoir", + "receiveTitle": "Recevoir des fonds onchain" + }, + "bvnk": { + "verificationRequiredTitle": "Vérifiez votre identité", + "verificationRequiredDescription": "BVNK s'associe à Sumsub pour confirmer votre identité avant d'activer votre compte de financement. Cliquez sur « Vérification complète » pour commencer : cette page s'actualise automatiquement une fois que vous êtes approuvé et vos instructions apparaîtront ici.", + "verificationInReviewTitle": "Vérification en cours d'examen", + "verificationInReviewDescription": "Sumsub examine vos informations – cela ne prend généralement que quelques minutes. N'hésitez pas à revenir plus tard ; vos instructions apparaîtront ici dès que vous serez approuvé.", + "verificationFailedTitle": "La vérification de l'identité n'a pas été approuvée", + "verificationFailedDescription": "BVNK n’a pas pu vérifier votre identité : ce compte de financement ne peut pas être activé. Contactez le support si erreur.", + "fundingAccountProvisioningTitle": "Configuration de votre compte de financement", + "fundingAccountProvisioningDescription": "Nous y sommes presque : nous approvisionnons votre compte virtuel maintenant. Vos instructions apparaîtront ici dans un instant.", + "provisioningFailedTitle": "Nous n'avons pas pu terminer la configuration de votre compte", + "provisioningFailedDescription": "Échec du provisioning du compte de financement. Réessayez.", + "readyTitle": "Préparer vos instructions", + "readyDescription": "Votre compte de financement est prêt – vous récupérez vos coordonnées maintenant.", + "onrampProvisioningDetail": "Provisionnement d'un BVNK Wallet et d'une règle de paiement fiat → crypto pour ce Quote.", + "offrampProvisioningDetail": "Mise à disposition d'un paiement BVNK dédié Wallet pour cette devise.", + "simulateDeposit": "Simuler un dépôt", + "simulating": "Simuler...", + "depositSimulated": "Dépôt simulé" + }, + "lightspark": { + "verificationRequiredTitle": "Vérifiez votre identité", + "verificationRequiredDescription": "Nous devons confirmer votre identité avant d'activer votre compte de financement. Cette page s'actualise automatiquement une fois que vous êtes approuvé.", + "verificationInReviewTitle": "Vérification en cours d'examen", + "verificationInReviewDescription": "Vos coordonnées sont en cours de révision – cela ne prend généralement que quelques minutes. Vos instructions apparaîtront ici dès que vous serez approuvé.", + "verificationFailedTitle": "La vérification de l'identité n'a pas été approuvée", + "verificationFailedDescription": "Impossible de vérifier votre identité : ce compte de financement ne peut pas être activé. Contactez le support si erreur.", + "fundingAccountProvisioningTitle": "Configuration de votre compte", + "fundingAccountProvisioningDescription": "Nous y sommes presque : nous préparons votre compte de financement. Vos instructions apparaîtront ici dans un instant.", + "provisioningFailedTitle": "Nous n'avons pas pu terminer la configuration de votre compte", + "provisioningFailedDescription": "Une erreur s'est produite lors de la préparation de votre compte de financement. Veuillez réessayer.", + "readyTitle": "Préparer vos instructions", + "readyDescription": "Votre compte est prêt – vous récupérez vos coordonnées maintenant.", + "onrampProvisioningDetail": "Provisionnement de votre client Lightspark et détails du dépôt pour ce Quote.", + "offrampProvisioningDetail": "Mise à disposition d'un compte de paiement Lightspark juste à temps pour ce retrait.", + "simulateQuote": "Simuler Quote", + "simulating": "Simuler...", + "quoteSimulated": "Quote Simulé" + }, + "mural": { + "termsTitle": "Accepter les conditions de Mural Pay", + "termsDescription": "Mural Pay nécessite que Counterparty accepte les conditions hébergées avant que la vérification d'identité puisse commencer.", + "verificationRequiredTitle": "Vérifiez votre identité", + "verificationRequiredDescription": "Mural Pay a besoin du Counterparty pour effectuer la vérification hébergée avant d'activer un compte de financement.", + "verificationInReviewTitle": "Vérification en cours d'examen", + "verificationInReviewDescription": "Mural Pay examine le Counterparty. Les instructions de financement apparaîtront une fois la vérification approuvée.", + "verificationFailedTitle": "La vérification de l'identité n'a pas été approuvée", + "verificationFailedDescription": "Mural Pay n'a pas pu approuver ce Counterparty, un compte de financement ne peut donc pas être activé.", + "fundingAccountProvisioningTitle": "Configuration de votre compte de financement", + "fundingAccountProvisioningDescription": "Mural Pay active un compte de financement. Les coordonnées bancaires apparaîtront ici lorsqu’elles seront prêtes.", + "readyTitle": "Préparer vos instructions", + "readyDescription": "Votre compte de financement Mural Pay est prêt. Récupération des derniers détails maintenant.", + "onrampProvisioningDetail": "Provisionnement d'un compte de financement Mural Pay pour ce Counterparty.", + "offrampProvisioningDetail": "Vérification de la vérification de l'organisation Mural Pay avant retrait.", + "simulateDeposit": "Simuler un dépôt", + "simulating": "Simuler...", + "depositSimulated": "Dépôt simulé" + }, + "batchSend": { + "recipientStatusPending": "En attente", + "recipientStatusProcessing": "Traitement", + "recipientStatusConfirmed": "Terminé", + "recipientStatusFailed": "Échec", + "recipientStatusArchived": "Archivé", + "resultConfirmed": "Batch envoyé", + "resultPartiallyFailed": "Batch a partiellement échoué", + "resultFailed": "Échec de Batch", + "resultSubmitted": "Batch soumis", + "recipientsStep": "Destinataires", + "recipientsTitle": "Payer plusieurs destinataires", + "reviewStep": "Examen", + "reviewTitle": "Avis Batch", + "customToken": "Personnalisé Token", + "tokenUnavailableOnNetwork": "{currency} n'est pas disponible sur ce réseau.", + "importExceedsMaximumRecipients": "Un Batch peut avoir au plus des destinataires {max}. Cette importation porterait le total à {total}.", + "submitting": "Soumission de Batch.", + "someRecipientsDidNotReceiveFunds": "Certains bénéficiaires n'ont pas reçu de fonds.", + "status": "Statut : {status}", + "estimateFailed": "L'estimation a échoué.", + "recipientSingular": "Destinataire {count}", + "recipientPlural": "Destinataires {count}", + "yourWallet": "votre Wallet", + "maximumRecipients": "Un Batch peut avoir au plus des destinataires {count}.", + "insufficientBalance": "Solde insuffisant", + "walletsSelectedSingular": "{count} Wallet sélectionné", + "walletsSelectedPlural": "{count} Wallets sélectionné", + "from": "De", + "selectSourceWallet": "Sélectionnez une source Wallet", + "searchWallets": "Rechercher Wallets", + "asset": "Asset", + "selectAsset": "Sélectionnez un Asset", + "noAssets": "Ce Wallet n'a aucun élément disponible à envoyer.", + "selectRecipientWallets": "Sélectionnez le destinataire Wallets", + "bulkImport": "Ou importation groupée", + "searchCounterparty": "Rechercher Counterparty", + "paginationSummary": "{page} / {pageCount}", + "noCounterpartiesWithSolanaAddress": "Aucune contrepartie avec une adresse Solana.", + "noMatches": "Aucun match.", + "addRecipient": "Ajouter {name}", + "totalAmount": "Total {total} {asset}", + "totalOfAmount": "de {available} {asset}", + "reviewSummary": "{total} {asset} → {recipients}", + "transactionCountSingular": "Transaction {count}", + "transactionCountPlural": "Transactions {count}", + "source": "Source", + "transactionFees": "Frais de transactions", + "rentFees": "Frais de loyer", + "total": "Total", + "sponsoredFee": "0 SOL", + "sponsoredBy": "Sponsorisé par SDP via Kora", + "estimating": "Estimation…", + "resultSummary": "Destinataires {recipients} · Transactions {transactions}", + "viewOnExplorer": "Afficher sur l'explorateur", + "bulkImportAriaLabel": "Destinataires de l'importation groupée", + "bulkImportTitle": "Destinataires de l'importation groupée", + "bulkImportDescriptionBefore": "Coller des lignes de", + "bulkImportFields": "contrepartie_wallet_id, devise connue ou adresse Mint, montant", + "bulkImportDescriptionAfter": "dans n’importe quel champ, ou ajoutez-les un par un.", + "counterpartyWalletIdPlaceholder": "contrepartie_wallet_id", + "currencyOrMintPlaceholder": "devise ou Mint", + "amountPlaceholder": "montant", + "removeRow": "Supprimer la ligne {row}", + "addRecipientRow": "Ajouter un destinataire", + "rowError": "Ligne {row} : {message}", + "addAtLeastOneRecipient": "Ajoutez au moins un destinataire.", + "oneCurrencyRequired": "Toutes les lignes doivent utiliser une devise ou une adresse Mint (trouvée {currencies}).", + "walletNotFound": "Wallet introuvable : {id}", + "importFailed": "L'importation a échoué.", + "cancel": "Annuler", + "importing": "Importation…", + "import": "Importer" + }, + "manualInstructions": { + "copied": "{label} copié.", + "copyFailed": "Échec de la copie de {label}.", + "copy": "Copier", + "instructions": "Instructions", + "quoteSummary": "Quote Résumé", + "quoteSummaryDescription": "Tarification verrouillée pour cette instruction de financement.", + "finalAmount": "Montant final", + "depositAmount": "Montant du dépôt", + "feesIncluded": "Frais inclus", + "exchangeRate": "Taux de change", + "expires": "Expire", + "bankName": "Nom de la banque", + "routingNumber": "Numéro de routage", + "accountNumber": "Numéro de compte", + "walletAddress": "Adresse de Wallet", + "reference": "Référence", + "supportedRails": "Rails supportés", + "notes": "Remarques", + "depositAddress": "Adresse de dépôt", + "bankCode": "Code banque", + "paymentReference": "Référence de paiement", + "identityVerificationRequired": "Vérification d'identité requise", + "completeVerification": "Vérification complète", + "provisioningAccount": "BVNK approvisionne votre compte bancaire virtuel", + "verificationInReview": "Vérification en cours d'examen", + "provisioningFundingAccount": "Compte de financement de provisionnement", + "checkingVerificationStatus": "Vérification de l'état de vérification", + "manualFundingInstructions": "Instructions de financement manuel", + "defaultDescription": "Envoyez {amount} via un rail supporté. Incluez la référence exacte pour que le provider rattache le dépôt à ce Quote.", + "quotedAmount": "le montant indiqué", + "cryptoDeposit": "Dépôt {currency}", + "virtualAccount": "Compte virtuel {currency}", + "payin": "{currency} payer" + }, + "providerRisk": { + "close": "Fermer {title}", + "description": "Ce screening vérifie sanctions et signaux de conformité des providers connectés.", + "provider": "provider", + "analysis": "Analyse", + "noTrmAttribution": "Aucune attribution TRM", + "unavailable": "Indisponible", + "error": "Erreur", + "notAvailable": "N/D", + "dismiss": "Rejeter" + }, + "counterparty": { + "loadFailed": "Impossible de charger les contreparties", + "metadataMissing": "La réponse aux métadonnées Counterparty était vide.", + "validation": { + "required": "Obligatoire", + "invalidEmail": "E-mail invalide", + "invalidDate": "Entrez une date au format AAAA-MM-JJ.", + "dateMustBePast": "Ça doit être du passé.", + "invalidPhone": "Saisissez un numéro de téléphone au format E.164 (par exemple, +14155551234).", + "selectCountry": "Sélectionnez un pays.", + "selectState": "Sélectionnez un état." + }, + "addExternalAccount": "Ajouter un compte externe", + "addExternalAccountDescription": "Attachez un crypto Wallet pour ce Counterparty. L'adresse est examinée pour détecter les risques avant d'être ajoutée.", + "addCounterparty": "Ajouter Counterparty", + "created": "{name} créé", + "createdSuccess": "Counterparty créé", + "transferType": "Tapez", + "transferProvider": "provider", + "transferWallet": "Wallet", + "transferAmount": "Montant", + "transferStatus": "Statut", + "transferDate": "Date", + "allProviders": "Tous les providers", + "noFilteredTransactions": "Aucune transaction ne correspond aux filtres sélectionnés.", + "fullName": "Nom complet", + "createdLabel": "Créé", + "youDeposit": "Vous déposez", + "youSend": "Vous envoyez", + "recipientGets": "Le destinataire obtient", + "viewOnExplorer": "Afficher sur l'explorateur", + "deleted": "{name} supprimé", + "createdButUnavailable": "Counterparty a été créé mais n'a pas pu être chargé.", + "somethingWentWrong": "Quelque chose s'est mal passé", + "addCryptoAccount": "Ajouter un compte crypto", + "addCryptoAccountDescription": "Ajoutez optionnellement un crypto Wallet pour ce Counterparty. Vous pourrez le faire plus tard.", + "cryptoWallet": "Crypto Wallet", + "done": "Terminé", + "skip": "Sauter", + "displayName": "Nom d'affichage", + "individualNamePlaceholder": "Jeanne Smith", + "businessNamePlaceholder": "Acme Corp.", + "email": "Courriel", + "emailPlaceholder": "contact@exemple.com", + "externalId": "ID externe", + "optional": "(facultatif)", + "externalIdPlaceholder": "votre-identifiant-interne", + "firstName": "Prénom", + "firstNamePlaceholder": "Jeanne", + "lastName": "Nom de famille", + "lastNamePlaceholder": "Forgeron", + "dateOfBirth": "Date de naissance", + "phone": "Téléphone", + "phonePlaceholder": "+1 555 000 0000", + "line1": "Ligne 1", + "line1Placeholder": "123, rue Principale", + "line2": "Ligne 2", + "line2Placeholder": "Suite 400", + "city": "Ville", + "cityPlaceholder": "New York", + "postalCode": "Code postal", + "country": "Pays", + "selectCountry": "Sélectionnez un pays", + "searchCountries": "Rechercher des pays…", + "state": "État", + "selectState": "Sélectionnez l'état", + "searchStates": "Rechercher des états…", + "stateProvince": "État/Province", + "statePlaceholder": "New York", + "basics": "Les bases", + "entityType": "Type d'entité", + "individual": "Individuel", + "business": "Affaires", + "personalInfo": "Informations personnelles", + "address": "Adresse", + "back": "Retour", + "creating": "Création", + "create": "Créer", + "next": "Suivant", + "stepProgress": "Étape {current} de {total}", + "deleteCounterparty": "Supprimer Counterparty", + "deleteNamedCounterparty": "Etes-vous sûr de vouloir supprimer {name} ? Cela archivera le Counterparty et ses comptes.", + "deleteThisCounterparty": "Etes-vous sûr de vouloir supprimer ce Counterparty ?", + "cancel": "Annuler", + "deleting": "Suppression", + "delete": "Supprimer", + "basicInfo": "Informations de base", + "basicInfoDescription": "Saisissez le nom et les coordonnées du Counterparty.", + "personal": "Personnel", + "personalDetails": "Données personnelles", + "personalDetailsDescription": "Informations d’identité de cette personne.", + "location": "Emplacement", + "locationDescription": "Cela nous aide à vérifier qui ils sont et où ils sont basés.", + "review": "Examen", + "reviewCreate": "Réviser et créer", + "reviewCreateDescription": "Confirmez que tout semble correct avant de créer.", + "adding": "Ajout", + "screening": "Dépistage", + "addAccount": "Ajouter un compte", + "cryptoAccountAttached": "Compte crypto attaché", + "label": "Étiquette", + "accountLabelPlaceholder": "par ex. Alice's Solana Wallet", + "network": "Réseau", + "selectNetwork": "Sélectionnez le réseau", + "walletAddress": "Adresse de Wallet", + "destinationWalletAddress": "Adresse de destination Wallet", + "screeningUnavailable": "Impossible de screener cette adresse — screening conformité indisponible. L’ajouter quand même ?", + "screeningWarning": "Un ou plusieurs checks ont signalé ce Wallet ou ont échoué. L’ajouter quand même ?", + "holdToAddAnyway": "Attendez pour ajouter quand même", + "searchAddress": "Rechercher une adresse", + "searchAddressPlaceholder": "Rechercher une adresse ou une entreprise…", + "failedToLoadPlaceDetails": "Échec du chargement des détails du lieu", + "searchFailed": "La recherche a échoué", + "searching": "Recherche…", + "noMatches": "Aucune correspondance trouvée.", + "updating": "Mise à jour…", + "searchToPreviewAddress": "Rechercher pour prévisualiser l'adresse", + "complianceScreening": "Vérification de la conformité", + "checking": "Vérification…", + "directory": "Annuaire", + "directoryDescription": "Particuliers et entreprises enregistrés dans votre espace de travail.", + "noCounterparties": "Pas encore de contreparties", + "noCounterpartiesDescription": "Ajoutez votre premier individu ou entreprise pour commencer.", + "type": "Tapez", + "manageCounterparty": "Gérer Counterparty", + "counterpartyActions": "Actions Counterparty", + "transactionDetails": "Détails de la transaction", + "playgroundProductName": "Counterparty", + "counterpartyIdPathPlaceholder": "{counterpartyId}", + "playgroundCounterpartyIdPlaceholder": "ID Counterparty (par exemple, cpty_abc123)", + "listCounterparties": "Liste des contreparties", + "getCounterparty": "Obtenez Counterparty", + "createCounterparty": "Créer Counterparty", + "playgroundEmailPlaceholder": "contact@acme.com", + "selectEntityType": "Sélectionnez le type d'entité", + "updateCounterparty": "Mettre à jour Counterparty", + "updatedDisplayNamePlaceholder": "Nom d'affichage mis à jour", + "updatedEmailPlaceholder": "mise à jour@exemple.com", + "noTransactions": "Aucune transaction liée à ce Counterparty pour l'instant.", + "allTypes": "Tous types", + "identity": "Identité", + "personalInformation": "Informations personnelles", + "noPersonalInformation": "Aucune information personnelle au dossier.", + "externalAccounts": "Comptes externes", + "noExternalAccounts": "Pas encore de comptes externes.", + "addExternalAccountTitle": "Ajouter un compte externe", + "manage": "Gérer", + "details": "Détails", + "transactions": "Opérations", + "copyAddress": "Copier l'adresse", + "addressCopied": "Adresse copiée" + }, + "playground": { + "moonPay": "MoonPay", + "lightspark": "Lightspark", + "bvnk": "BVNK", + "walletIdPathLabel": "{walletId}", + "walletIdPlaceholder": "ID Wallet (par exemple, wal_ops_123)", + "transferIdPathLabel": "{transferId}", + "transferIdPlaceholder": "ID Transfer (par exemple, xfr_123)", + "custodyWalletIdPlaceholder": "ID Wallet de garde (par exemple, wal_ops_123)", + "destinationWalletIdPlaceholder": "ID Wallet de destination", + "sourceWalletIdPlaceholder": "Identifiant source Wallet", + "getWalletBalances": "Obtenez les soldes Wallet", + "getWalletPolicy": "Obtenir la politique Wallet", + "updateWalletPolicy": "Mettre à jour la politique Wallet", + "destinationAllowlistPlaceholder": "Adresses de destination séparées par des virgules", + "executeTransfer": "Exécuter Transfer", + "solanaAddressPlaceholder": "Adresse Solana (32-44 caractères)", + "usdc": "USDC", + "optionalMemo": "memo en option", + "listTransfers": "Liste des Transfers", + "getTransfer": "Obtenez Transfer", + "createOnrampQuote": "Créer Onramp Quote", + "selectProvider": "Sélectionnez le provider", + "counterpartyIdPlaceholder": "ID Counterparty (par exemple, cpty_abc123)", + "selectFiatCurrency": "Sélectionnez la monnaie fiduciaire", + "onrampRedirectUrlPlaceholder": "https://app.example.com/payments/Zonramp/complete", + "createOfframpQuote": "Créer Offramp Quote", + "offrampRedirectUrlPlaceholder": "https://app.example.com/payments/Zofframp/complete" + }, + "totalSdpBalance": "Solde total du SDP", + "aggregatedAcrossWallets": "Agrégé sur {count} {walletLabel}.", + "wallet": "Wallet", + "wallets": "Wallets", + "noUsdValuedAssets": "Aucune ligne Asset évaluée en USD n'est encore disponible.", + "recentTransactions": "Opérations récentes", + "recentTransactionsDescription": "Dernière activité Transfer dans toute l'organisation Wallets.", + "refreshing": "Rafraîchissant...", + "refresh": "Actualiser", + "noTransactions": "Aucune transaction trouvée pour l'instant.", + "status": "Statut", + "transfer": "Transfer", + "asset": "Asset", + "direction": "Direction", + "counterpartyLabel": "Counterparty", + "signature": "Signature", + "createdLabel": "Créé", + "pending": "En attente", + "expired": "Expiré", + "unknown": "Inconnu", + "unavailable": "Indisponible", + "deposit": "Dépôt", + "pay": "Payer", + "transferDetails": { + "providerFee": "Frais du provider", + "networkFee": "Frais de réseau", + "exchangeRate": "Taux de change", + "fees": "Frais", + "provider": "provider", + "transactionId": "ID de transaction", + "providerReference": "Référence du provider", + "memo": "Memo", + "cashPickupCode": "Code de retrait d'espèces", + "moneygramTransactionId": "ID de transaction MoneyGram", + "payoutStatus": "Statut de paiement", + "payoutAmount": "Montant du paiement", + "cryptoTransferId": "Identifiant cryptographique Transfer", + "solanaSignature": "Solana signature", + "moneygramError": "Erreur MoneyGram", + "lastUpdated": "Dernière mise à jour", + "copy": "Copier {label}" + }, + "requestFailed": "La demande a échoué.", + "recurringPaymentsUnavailable": "Paiements Recurring indisponibles", + "submitting": "Envoi...", + "sendTransfer": "Envoyer Transfer", + "sendBatch": "Envoyer Batch", + "reviewAction": "Examen", + "processing": "Traitement", + "verificationPending": "Vérification en attente", + "completeVerification": "Vérification complète", + "previous": "Précédent", + "goToTransaction": "Aller à la transaction", + "method": "Méthode", + "whoAreYouPaying": "Qui payez-vous ?", + "whoIsThisDepositFrom": "De qui provient ce dépôt ?", + "howWouldYouLikeToPay": "Comment souhaiteriez-vous payer ?", + "howWouldYouLikeToDeposit": "Comment souhaitez-vous effectuer un dépôt ?", + "poweredBy": "Alimenté par", + "playgroundProductName": "Paiements", + "recurring": { + "emptyResponse": "{request} a renvoyé une réponse vide.", + "counterpartyStepTitle": "À qui est destiné ce paiement Recurring ?", + "destination": "Destination", + "destinationStepTitle": "Où doivent aller les paiements ?", + "details": "Détails", + "detailsStepTitle": "Définir les détails du paiement", + "reviewStepTitle": "Vérifier le paiement Recurring", + "everyDay": "Chaque jour", + "collectDaily": "Collectez une fois par jour.", + "everyWeek": "Chaque semaine", + "collectWeekly": "Collectez une fois par semaine.", + "everyThirtyDays": "Tous les 30 jours", + "collectMonthly": "Collectez environ une fois par mois.", + "custom": "Personnalisé", + "customScheduleDescription": "Entrez un intervalle en heures.", + "notSet": "Non défini", + "customInterval": "Intervalle personnalisé", + "everyHour": "Toutes les heures", + "everyHours": "Toutes les heures {count}", + "notSelected": "Non sélectionné", + "destinationAccount": "Compte de destination", + "fundingWallet": "Financement Wallet", + "amount": "Montant", + "billingInterval": "Intervalle de facturation", + "firstPayment": "Premier paiement", + "afterActivation": "Après activation", + "metadata": "Métadonnées", + "creatingPayment": "Création du paiement Recurring.", + "paymentCreated": "Paiement Recurring créé.", + "pendingActivationDescription": "Il est en attente d'activation.", + "unableToCreate": "Impossible de créer le paiement Recurring.", + "paymentNotCreated": "Le paiement Recurring n'a pas été créé.", + "createPayment": "Créer un paiement Recurring", + "loadingAccounts": "Chargement des comptes", + "noSolanaAccounts": "Aucun compte Solana enregistré", + "selectDestinationAccount": "Sélectionnez un compte de destination", + "searchAccounts": "Rechercher des comptes", + "needsCryptoAccount": "Ce Counterparty nécessite un compte crypto Wallet Solana actif avant de pouvoir créer un paiement Recurring.", + "addSolanaAddress": "Ajouter l'adresse Solana", + "noDestinationWallet": "{name} n’a pas encore de destination Wallet dans ses fichiers.", + "attachDestinationWallet": "Attachez une autre destination Wallet pour ce Counterparty.", + "selectFundingWallet": "Sélectionnez un financement Wallet", + "searchWallets": "Rechercher Wallets", + "asset": "Asset", + "noTokenBalances": "Aucun solde Token pris en charge", + "selectAsset": "Sélectionnez un Asset", + "selectWalletFirst": "Sélectionnez d'abord un Wallet", + "searchAssets": "Rechercher des Assets", + "unresolvedTokenBalances": "Ce Wallet a des soldes Token, mais leurs symboles n'ont pas encore pu être résolus.", + "nativeSolUnsupported": "Les paiements Recurring nécessitent un solde Token. Le SOL natif n'est pas pris en charge.", + "invalidAmount": "Entrez un montant supérieur à zéro.", + "intervalHours": "Intervalle en heures", + "invalidInterval": "Saisissez un nombre entier d'heures compris entre 1 et 8760.", + "invalidFirstPayment": "Choisissez une date et une heure futures.", + "startAfterActivation": "Laissez vide pour démarrer après l'activation.", + "metadataUrl": "URL des métadonnées", + "metadataUrlPlaceholder": "https://example.com/metadata.json", + "invalidMetadataUrl": "Saisissez une URL valide de moins de 128 caractères.", + "optional": "Facultatif.", + "pendingRecordDescription": "Cela crée un enregistrement de paiement Recurring en attente. L'activation est une étape distincte.", + "pendingActivation": "En attente d'activation", + "activating": "Activation", + "active": "Actif", + "updating": "Mise à jour", + "canceling": "Annulation", + "resuming": "Reprise", + "paused": "En pause", + "canceled": "Annulé", + "expired": "Expiré", + "pending": "En attente", + "processing": "Traitement", + "collected": "Collecté", + "failed": "Échec", + "skipped": "Sauté", + "recurringPayments": "Paiements Recurring", + "recurringPaymentCount": "Paiements {count} Recurring", + "oneRecurringPayment": "1 paiement Recurring", + "unableToLoad": "Impossible de charger les paiements Recurring", + "noPayments": "Aucun paiement Recurring pour l’instant.", + "paymentsAppearHere": "Les enregistrements de paiement Recurring créés apparaîtront ici.", + "interval": "Intervalle", + "nextPayment": "Prochain paiement", + "counterpartyUnavailable": "Counterparty indisponible", + "payment": "Paiement Recurring", + "receivingWallet": "Réception de Wallet", + "starts": "Commence", + "currency": "Devise", + "paymentReference": "Référence de paiement", + "openMetadata": "Métadonnées ouvertes", + "created": "Créé", + "updated": "Mis à jour", + "edit": "Modifier", + "copyValue": "Copier la valeur", + "copied": "Copié", + "openSignature": "Ouvrir signature", + "collectionHistory": "Historique des collections", + "showingAttempts": "Affichage de {shown} sur {total} tentatives", + "oneAttempt": "1 tentative", + "attempts": "{count} tentatives", + "unableToLoadCollectionHistory": "Impossible de charger l'historique de collecte : {error}", + "noCollectionAttempts": "Aucune tentative de collecte pour l'instant. La prochaine collecte programmée est indiquée ci-dessus.", + "due": "Due", + "attempted": "Tentative", + "transfer": "Transfer", + "explorer": "Explorateur", + "everyWeeks": "Toutes les semaines {count}", + "everyDays": "Tous les jours {count}", + "paymentActivated": "Paiement Recurring activé.", + "collectionSubmitted": "Recouvrement de paiement Recurring soumis.", + "paymentCanceled": "Paiement Recurring annulé.", + "paymentResumed": "Le paiement Recurring a repris.", + "activationFailed": "L'activation a échoué", + "collectionFailed": "Échec de la collecte", + "cancellationFailed": "Échec de l'annulation", + "resumeFailed": "La reprise a échoué", + "retryActivation": "Réessayer l'activation", + "activate": "Activer", + "retryCollection": "Réessayer la collecte", + "collectNow": "Collectionnez maintenant", + "retryResume": "Réessayez de reprendre", + "resume": "CV", + "retryCancellation": "Réessayer l'annulation", + "cancel": "Annuler", + "actions": "Actions", + "editPayment": "Modifier le paiement", + "stopFutureCollections": "Arrêter les futures collectes", + "copyError": "Erreur de copie", + "readyToActivate": "Prêt à activer", + "readyToActivateDescription": "Crée l'abonnement et planifie le premier paiement.", + "lifecycleActionUnavailable": "Action de cycle de vie indisponible", + "lifecycleActionUnavailableDescription": "Ce paiement Recurring ne peut pas être modifié par rapport à son statut actuel.", + "updatingPayment": "Mise à jour du paiement Recurring.", + "actionFailed": "L'action de paiement Recurring a échoué.", + "alreadyFundingWallet": "{wallet} est déjà le financement Wallet.", + "updatingFundingWallet": "Mise à jour du financement Wallet.", + "fundingWalletUpdated": "Financement Wallet mis à jour.", + "fundingWalletUpdateFailed": "Échec de la mise à jour du financement de Wallet", + "paymentUpdateFailed": "Échec de la mise à jour du paiement Recurring.", + "selectReceivingWallet": "Sélectionnez un Wallet de réception.", + "alreadyReceivingWallet": "{wallet} est déjà le Wallet récepteur.", + "updatingReceivingWallet": "Mise à jour de la réception de Wallet.", + "receivingWalletUpdated": "Réception de Wallet mise à jour.", + "receivingWalletUpdateFailed": "Échec de la réception de la mise à jour Wallet", + "alreadySet": "{value} est déjà défini.", + "updatingBillingInterval": "Mise à jour de l'intervalle de facturation.", + "billingIntervalUpdated": "Intervalle de facturation mis à jour.", + "billingIntervalUpdateFailed": "Échec de la mise à jour de l'intervalle de facturation", + "selectCurrency": "Sélectionnez une devise.", + "alreadyCurrency": "{currency} est déjà la devise.", + "updatingCurrency": "Mise à jour de la devise.", + "currencyUpdated": "Devise mise à jour.", + "currencyUpdateFailed": "Échec de la mise à jour de la devise", + "updatingAmount": "Mise à jour du montant.", + "amountUpdated": "Montant mis à jour.", + "amountUpdateFailed": "Échec de la mise à jour du montant", + "editFundingWallet": "Modifier le financement Wallet", + "editFundingWalletDescription": "Choisissez le Wallet utilisé pour financer ce paiement Recurring.", + "editReceivingWallet": "Modifier la réception de Wallet", + "editReceivingWalletDescription": "Choisissez où ce paiement Recurring envoie les fonds.", + "editAmount": "Modifier le montant", + "editAmountDescription": "Définissez le montant collecté à chaque période de facturation.", + "editBillingInterval": "Modifier l'intervalle de facturation", + "editBillingIntervalDescription": "Choisissez la fréquence à laquelle ce paiement Recurring doit être collecté.", + "editCurrency": "Modifier la devise", + "editCurrencyDescription": "Choisissez un solde Token parmi le financement Wallet.", + "cancelPaymentTitle": "Annuler le paiement Recurring ?", + "cancelPaymentDescription": "Cela arrête les futures collectes pour {counterparty}. Vous pourrez reprendre le paiement ultérieurement depuis le menu Actions.", + "keepPayment": "Conserver le paiement", + "cancelPayment": "Annuler le paiement", + "save": "Enregistrer" + }, + "requests": { + "loadFailed": "Impossible de charger les demandes de paiement", + "awaitingPayment": "En attente de paiement", + "paid": "Payé", + "canceled": "Annulé", + "expired": "Expiré", + "paymentLinkCreated": "Lien de paiement créé", + "createPaymentRequest": "Créer une demande de paiement", + "createPaymentLink": "Créer un lien de paiement", + "createPaymentLinkDescription": "Demandez un paiement forfaitaire à l’un de vos Wallets.", + "amount": "Montant", + "token": "Token", + "selectToken": "Sélectionnez Token", + "destinationWallet": "Destination Wallet", + "selectWallet": "Sélectionnez Wallet", + "fromCounterparty": "De (Counterparty)", + "anyoneWithLink": "Quelqu'un ayant le lien", + "loadingCryptoAccount": "Chargement du compte crypto…", + "paysFrom": "Paye à partir de", + "noCryptoAccount": "Aucun compte crypto dans le dossier.", + "add": "Ajouter", + "linkExpires": "Le lien expire", + "noExpiry": "Pas d'expiration", + "oneHour": "1 heure", + "twentyFourHours": "24 heures", + "sevenDays": "7 jours", + "thirtyDays": "30 jours", + "cancel": "Annuler", + "creating": "Création…", + "createLink": "Créer un lien", + "paymentRequests": "Demandes de paiement", + "paymentRequestsDescription": "Liens partageables qui demandent un paiement fixe.", + "create": "Créer", + "noPaymentRequests": "Aucune demande de paiement pour l'instant", + "noPaymentRequestsDescription": "Créez un lien de paiement pour demander un paiement fixe.", + "from": "De", + "to": "À", + "paymentRequestDetails": "Détails de la demande de paiement", + "paymentRequest": "Demande de paiement", + "amountRequested": "Montant demandé", + "paymentLinkCopied": "Lien de paiement copié", + "copy": "Copier", + "reference": "Référence", + "expires": "Expire", + "destinationWalletId": "ID Wallet de destination", + "splMintAddress": "Adresse de SPL Mint", + "listRequests": "Liste des demandes de paiement", + "createRequest": "Créer une demande de paiement", + "playgroundProductName": "Demandes de paiement" + } + } +} diff --git a/apps/sdp-web/messages/fr/shared.json b/apps/sdp-web/messages/fr/shared.json new file mode 100644 index 000000000..5e7c12762 --- /dev/null +++ b/apps/sdp-web/messages/fr/shared.json @@ -0,0 +1,198 @@ +{ + "tabs": { + "overview": "Aperçu", + "apiPlayground": "API Playground" + }, + "authTerms": { + "prefix": "En utilisant l’app, vous acceptez les", + "link": "Conditions d’utilisation Solana Foundation" + }, + "homeSignedIn": { + "loading": "Chargement...", + "selectOrganization": "Sélectionnez votre organisation", + "selectOrganizationDescription": "Choisissez ou créez une organisation pour continuer.", + "loadingDashboard": "Chargement du dashboard..." + }, + "allowlist": { + "comingSoon": "Bientôt disponible", + "description": "La gestion Allowlist arrivera dans une prochaine version." + }, + "members": { + "comingSoon": "Bientôt disponible", + "description": "La gestion des membres arrivera dans une prochaine version." + }, + "SharedComponents": { + "copied": "Copié", + "copy": "Copier", + "apiDebugLogs": "Logs debug API", + "pause": "Pause", + "resume": "Reprendre", + "requestSummary": "Méthode, durée, résumé à copier", + "query": "Query", + "requestBody": "Corps de la requête", + "response": "Réponse", + "createApiKey": "Créer une clé API", + "selectApiKey": "Sélectionner une clé API", + "selectOrganization": "Sélectionner une organisation", + "organizations": "Organisations", + "projects": "Projets", + "current": "Actuel", + "noOrganizations": "Aucune organisation.", + "noProjects": "Aucun projet.", + "locked": "Verrouillé", + "sandboxOnly": "Seul le mode Sandbox est pris en charge pour l’instant.", + "mainnetSoon": "Support Mainnet bientôt disponible.", + "createOrganization": "Créer une organisation", + "manageOrganization": "Gérer l’organisation", + "clear": "Effacer", + "disable": "Désactiver", + "collapse": "Réduire", + "close": "Fermer", + "closeModal": "Fermer la fenêtre", + "noRequests": "Aucune requête capturée.", + "noPayload": "Aucune query, corps ou réponse capturée.", + "selectApiEndpoint": "Sélectionner un endpoint API", + "request": "Requête", + "output": "Sortie", + "pathParameters": "Paramètres de chemin", + "noPathParameters": "Cet endpoint n’exige pas de paramètres de chemin.", + "selectValue": "Sélectionner une valeur", + "noRequestBody": "Cet endpoint n’exige pas de corps JSON.", + "status": "Statut :", + "apiKeyRequired": "Créez d’abord une clé API pour activer les requêtes live.", + "runRequest": "Exécuter", + "reset": "Réinitialiser", + "retry": "Réessayer", + "copyCode": "Copier le code", + "code": "Code", + "example": "Exemple", + "pending": "En attente", + "durationMilliseconds": "{duration}ms", + "networkDebugSummary": "{pending} en attente, {completed} terminées", + "aiInstructions": "Instructions IA", + "pageOf": "Page {page} sur {pageCount}", + "previousPage": "Page précédente", + "nextPage": "Page suivante", + "loading": "Chargement…", + "noOptionsAvailable": "Aucune option disponible.", + "noSearchMatches": "Aucun résultat pour votre recherche.", + "required": "(requis)", + "selectAnOption": "Sélectionner une option", + "search": "Rechercher…", + "fillBeforeSending": "à remplir avant l’envoi", + "noValue": "- aucun", + "aiInstructionIntro": "Utilisez l’endpoint API {productName} {method} {path}.", + "aiPathParameters": "Paramètres de chemin :", + "aiRequestBody": "Corps de la requête :", + "aiInstructionOutro": "Renvoyez le corps de réponse en JSON formaté et signalez toute erreur de validation ou d’auth.", + "runRequestToInspectOutput": "Exécutez la requête pour inspecter la sortie API live de cet endpoint.", + "requestFailed": "Échec de la requête", + "ready": "Prêt", + "completeRequiredFields": "Complétez les champs requis : {fields}", + "invalidApiKeyFormat": "Format de clé API invalide. Utilisez une clé brute comme sk_test_... ou sk_live_... avec un suffixe valide.", + "playgroundExecutionFailed": "Échec de l’exécution Playground.", + "requestExecutionFailed": "Échec de l’exécution de la requête." + }, + "dashboardShell": { + "openNavigation": "Ouvrir la navigation", + "closeNavigation": "Fermer la navigation", + "sandbox": "Sandbox", + "loadingDashboard": "Chargement du dashboard...", + "signInToContinue": "Connectez-vous pour continuer", + "signInDescription": "Accédez à votre espace organisation et aux contrôles Wallet.", + "signIn": "Se connecter", + "selectOrganization": "Sélectionner une organisation", + "selectOrganizationDescription": "Une organisation est requise pour continuer.", + "counterparty": "Counterparty", + "pay": "Payer", + "deposit": "Déposer", + "requests": "Demandes", + "recurring": "Récurrents", + "create": "Créer", + "manage": "Gérer", + "home": "Accueil", + "wallets": "Wallets", + "issuance": "Émission", + "payments": "Paiements", + "apiKeys": "Clés API", + "apiDocs": "Docs API", + "settings": "Paramètres", + "collapseSidebar": "Réduire la barre latérale", + "expandSidebar": "Étendre la barre latérale", + "closeNavigationOverlay": "Fermer la navigation", + "newCounterparty": "Nouveau Counterparty", + "manageCounterparty": "Gérer Counterparty", + "backToCounterparty": "Retour Counterparty", + "backToWallets": "Retour aux Wallets", + "backToWalletDetail": "Retour au détail Wallet", + "createWallet": "Créer un Wallet", + "activateProvider": "Activer le provider", + "newAsset": "Nouvel Asset", + "backToOverview": "Retour à l’aperçu", + "recurringPayments": "Paiements récurrents", + "recurringPayment": "Paiement récurrent", + "backToRecurringPayments": "Retour aux paiements récurrents", + "receive": "Recevoir", + "send": "Envoyer", + "backToPayments": "Retour aux paiements", + "members": "Membres", + "allowlist": "Allowlist" + }, + "validation": { + "allowlistValueRequired": "La valeur Allowlist est requise", + "allowlistEntryIdRequired": "L’ID d’entrée Allowlist est requis", + "emailRequired": "L’e-mail est requis" + }, + "pay": { + "productName": "Solana Developer Platform", + "paymentReceived": "Paiement reçu", + "paymentReceivedDescription": "Cette demande a été payée. Rien d’autre à faire.", + "linkExpired": "Lien expiré", + "linkExpiredDescription": "Ce lien de paiement n’est plus valide. Demandez-en un nouveau à l’expéditeur.", + "requestCanceled": "Demande annulée", + "requestCanceledDescription": "Cette demande de paiement a été annulée par l’expéditeur.", + "paymentRequest": "Demande de paiement", + "scanWallet": "Scannez avec un Wallet Solana pour payer", + "openWallet": "Ouvrir dans le Wallet", + "to": "À", + "token": "Token", + "expires": "Expire", + "noExpiry": "Sans expiration", + "securedBySolanaPay": "Sécurisé par Solana Pay", + "qrCode": "QR code Solana Pay" + }, + "homeWorkspace": { + "unavailable": "Indisponible", + "createFirstWalletBalances": "Créez votre premier Wallet pour suivre les soldes.", + "noTrackedBalances": "Aucun solde suivi pour l’instant.", + "activityUnavailable": "L’activité est indisponible pour le moment.", + "paymentActivityAfterWallet": "L’activité de paiement apparaîtra après la création d’un Wallet.", + "noPaymentVolume": "Aucun volume de paiement enregistré.", + "loadingPaymentActivity": "Chargement de l’activité de paiement...", + "createFirstWalletActivity": "Créez votre premier Wallet pour suivre soldes et activité.", + "noRecentActivity": "Aucune activité récente.", + "loadingRecentActivity": "Chargement de l’activité récente...", + "createWallet": "Créer un Wallet", + "totalBalance": "Solde total", + "todaysVolume": "Volume du jour", + "recentTransactions": "Transactions récentes", + "activityDescription": "Dernière activité Wallet et émission dans l’organisation.", + "seeAllPayments": "Voir tous les paiements", + "time": "Heure", + "activity": "Activité", + "type": "Type", + "token": "Token", + "amount": "Montant", + "address": "Adresse", + "send": "Envoyer", + "receive": "Recevoir", + "transfer": "Transfer", + "untitledToken": "Token sans titre", + "unableToLoadIssuanceTokens": "Impossible de charger les Tokens d’émission", + "someIssuanceActivityUnavailable": "Une partie de l’activité d’émission n’a pas pu être chargée.", + "paymentsActivityUnavailable": "L’activité paiements est indisponible pour le moment.", + "issuanceActivityUnavailable": "L’activité d’émission est indisponible pour le moment.", + "failedToLoadActivity": "Échec du chargement de l’activité du dashboard", + "balanceDataUnavailable": "Les données de solde sont indisponibles pour le moment." + } +} diff --git a/apps/sdp-web/src/i18n/README.md b/apps/sdp-web/src/i18n/README.md index dcd385aae..af24067b5 100644 --- a/apps/sdp-web/src/i18n/README.md +++ b/apps/sdp-web/src/i18n/README.md @@ -2,6 +2,8 @@ The dashboard keeps its supported BCP-47 locales in `config.ts` and its English source catalog in `../../messages/en.json`. +Supported locales today: `en`, `fr`. French catalogs live under `../../messages/fr/` and must keep a 100% matching key inventory with English. + Use `await getTranslations()` in Server Components and `useTranslations()` in Client Components. Both accept only keys that exist in the English catalog. For dates, numbers, lists, and relative time, construct the native `Intl` formatter with the resolved locale rather than pinning it to `en-US`. To add a locale, add its BCP-47 tag to `supportedLocales`, add a same-shaped catalog, and register it in `messagesByLocale`. The request resolver gives a valid locale cookie priority, then uses `Accept-Language`, falling back to English. A future language picker should persist its selection in the `sdp-locale` cookie. diff --git a/apps/sdp-web/src/i18n/config.ts b/apps/sdp-web/src/i18n/config.ts index 73997bd0f..51ebd22df 100644 --- a/apps/sdp-web/src/i18n/config.ts +++ b/apps/sdp-web/src/i18n/config.ts @@ -1,4 +1,4 @@ -export const supportedLocales = ["en"] as const; +export const supportedLocales = ["en", "fr"] as const; export type AppLocale = (typeof supportedLocales)[number]; diff --git a/apps/sdp-web/src/i18n/messages.ts b/apps/sdp-web/src/i18n/messages.ts index 8540fc00c..a594c8617 100644 --- a/apps/sdp-web/src/i18n/messages.ts +++ b/apps/sdp-web/src/i18n/messages.ts @@ -1,20 +1,33 @@ import type { AppLocale } from "@/i18n/config"; -import dashboardCustody from "../../messages/en/dashboard-custody.json"; -import dashboardIssuance from "../../messages/en/dashboard-issuance.json"; -import dashboardPayments from "../../messages/en/dashboard-payments.json"; -import shared from "../../messages/en/shared.json"; +import enDashboardCustody from "../../messages/en/dashboard-custody.json"; +import enDashboardIssuance from "../../messages/en/dashboard-issuance.json"; +import enDashboardPayments from "../../messages/en/dashboard-payments.json"; +import enShared from "../../messages/en/shared.json"; import en from "../../messages/en.json"; +import frDashboardCustody from "../../messages/fr/dashboard-custody.json"; +import frDashboardIssuance from "../../messages/fr/dashboard-issuance.json"; +import frDashboardPayments from "../../messages/fr/dashboard-payments.json"; +import frShared from "../../messages/fr/shared.json"; +import fr from "../../messages/fr.json"; const enMessages = { ...en, - ...dashboardCustody, - ...dashboardIssuance, - ...dashboardPayments, - Shared: shared, + ...enDashboardCustody, + ...enDashboardIssuance, + ...enDashboardPayments, + Shared: enShared, }; export type Messages = typeof enMessages; +const frMessages = { + ...fr, + ...frDashboardCustody, + ...frDashboardIssuance, + ...frDashboardPayments, + Shared: frShared, +} as Messages; + export type MessageKeyFor = TValue extends string ? "" : { @@ -26,7 +39,10 @@ export type MessageKeyFor = TValue extends string export type MessageKey = MessageKeyFor; export type TranslationValues = Record; -const messagesByLocale: Record = { en: enMessages }; +const messagesByLocale: Record = { + en: enMessages, + fr: frMessages, +}; export function getMessages(locale: AppLocale): Messages { return messagesByLocale[locale]; diff --git a/apps/sdp-web/src/i18n/messages.unit.test.ts b/apps/sdp-web/src/i18n/messages.unit.test.ts index c611f031f..3687fc05d 100644 --- a/apps/sdp-web/src/i18n/messages.unit.test.ts +++ b/apps/sdp-web/src/i18n/messages.unit.test.ts @@ -1,15 +1,43 @@ import { describe, expect, it } from "vitest"; -import { isAppLocale } from "@/i18n/config"; +import { isAppLocale, supportedLocales } from "@/i18n/config"; import { getMessages, translate } from "@/i18n/messages"; +function flattenKeys(value: unknown, prefix = ""): string[] { + if (typeof value === "string") { + return [prefix]; + } + + if (!value || typeof value !== "object") { + return []; + } + + return Object.entries(value).flatMap(([key, nested]) => { + const next = prefix ? `${prefix}.${key}` : key; + return flattenKeys(nested, next); + }); +} + describe("i18n messages", () => { it("only accepts configured locales", () => { expect(isAppLocale("en")).toBe(true); - expect(isAppLocale("fr")).toBe(false); + expect(isAppLocale("fr")).toBe(true); + expect(isAppLocale("de")).toBe(false); }); it("resolves typed catalog entries", () => { expect(translate(getMessages("en"), "Home.joinWaitlist")).toBe("Join the waitlist"); + expect(translate(getMessages("fr"), "Home.joinWaitlist")).toBe( + "Rejoindre la liste d’attente" + ); + }); + + it("keeps non-English catalogs inventory-matched to English", () => { + const englishKeys = flattenKeys(getMessages("en")).sort(); + + for (const locale of supportedLocales) { + if (locale === "en") continue; + expect(flattenKeys(getMessages(locale)).sort()).toEqual(englishKeys); + } }); it("rejects missing interpolation values", () => { From c91975658e070d6dfc9b6f0d7efbbf8bc3cc1bc7 Mon Sep 17 00:00:00 2001 From: Tomie <49788015+tomiet@users.noreply.github.com> Date: Mon, 13 Jul 2026 12:53:48 -0400 Subject: [PATCH 2/6] fix(web): translate new language picker strings in French Keep the fr shared catalog inventory-matched after upstream language picker landed on main. Co-authored-by: Cursor --- apps/sdp-web/messages/fr/shared.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/sdp-web/messages/fr/shared.json b/apps/sdp-web/messages/fr/shared.json index 5e7c12762..4617e8107 100644 --- a/apps/sdp-web/messages/fr/shared.json +++ b/apps/sdp-web/messages/fr/shared.json @@ -117,6 +117,9 @@ "apiKeys": "Clés API", "apiDocs": "Docs API", "settings": "Paramètres", + "language": "Langue", + "chooseLanguage": "Choisir la langue", + "moreLanguagesHint": "D’autres langues apparaîtront ici dès qu’elles seront disponibles.", "collapseSidebar": "Réduire la barre latérale", "expandSidebar": "Étendre la barre latérale", "closeNavigationOverlay": "Fermer la navigation", From ce8fb62211a4af59822f7f41be3afb3458d56f1c Mon Sep 17 00:00:00 2001 From: Tomie <49788015+tomiet@users.noreply.github.com> Date: Mon, 13 Jul 2026 13:08:51 -0400 Subject: [PATCH 3/6] fix(web): use Transfert consistently in French catalogs Align home and payments activity labels with custody so Transfer is not left in English mid-French UI. Co-authored-by: Cursor --- apps/sdp-web/messages/fr/dashboard-payments.json | 4 ++-- apps/sdp-web/messages/fr/shared.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sdp-web/messages/fr/dashboard-payments.json b/apps/sdp-web/messages/fr/dashboard-payments.json index 3f40f9482..cf8ff3c8d 100644 --- a/apps/sdp-web/messages/fr/dashboard-payments.json +++ b/apps/sdp-web/messages/fr/dashboard-payments.json @@ -635,7 +635,7 @@ "refresh": "Actualiser", "noTransactions": "Aucune transaction trouvée pour l'instant.", "status": "Statut", - "transfer": "Transfer", + "transfer": "Transfert", "asset": "Asset", "direction": "Direction", "counterpartyLabel": "Counterparty", @@ -788,7 +788,7 @@ "noCollectionAttempts": "Aucune tentative de collecte pour l'instant. La prochaine collecte programmée est indiquée ci-dessus.", "due": "Due", "attempted": "Tentative", - "transfer": "Transfer", + "transfer": "Transfert", "explorer": "Explorateur", "everyWeeks": "Toutes les semaines {count}", "everyDays": "Tous les jours {count}", diff --git a/apps/sdp-web/messages/fr/shared.json b/apps/sdp-web/messages/fr/shared.json index 4617e8107..305083166 100644 --- a/apps/sdp-web/messages/fr/shared.json +++ b/apps/sdp-web/messages/fr/shared.json @@ -189,7 +189,7 @@ "address": "Adresse", "send": "Envoyer", "receive": "Recevoir", - "transfer": "Transfer", + "transfer": "Transfert", "untitledToken": "Token sans titre", "unableToLoadIssuanceTokens": "Impossible de charger les Tokens d’émission", "someIssuanceActivityUnavailable": "Une partie de l’activité d’émission n’a pas pu être chargée.", From 41193e05298eae88a37d2ae34e4dbcc775980a99 Mon Sep 17 00:00:00 2001 From: Tomie <49788015+tomiet@users.noreply.github.com> Date: Tue, 14 Jul 2026 14:45:57 -0600 Subject: [PATCH 4/6] fix(web): drop stale French payments keys removed upstream Keep the fr catalog inventory-matched after English playground path placeholders were deleted on main. Co-authored-by: Cursor --- apps/sdp-web/messages/fr/dashboard-payments.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/sdp-web/messages/fr/dashboard-payments.json b/apps/sdp-web/messages/fr/dashboard-payments.json index cf8ff3c8d..75c92c5b4 100644 --- a/apps/sdp-web/messages/fr/dashboard-payments.json +++ b/apps/sdp-web/messages/fr/dashboard-payments.json @@ -571,7 +571,6 @@ "counterpartyActions": "Actions Counterparty", "transactionDetails": "Détails de la transaction", "playgroundProductName": "Counterparty", - "counterpartyIdPathPlaceholder": "{counterpartyId}", "playgroundCounterpartyIdPlaceholder": "ID Counterparty (par exemple, cpty_abc123)", "listCounterparties": "Liste des contreparties", "getCounterparty": "Obtenez Counterparty", @@ -599,9 +598,7 @@ "moonPay": "MoonPay", "lightspark": "Lightspark", "bvnk": "BVNK", - "walletIdPathLabel": "{walletId}", "walletIdPlaceholder": "ID Wallet (par exemple, wal_ops_123)", - "transferIdPathLabel": "{transferId}", "transferIdPlaceholder": "ID Transfer (par exemple, xfr_123)", "custodyWalletIdPlaceholder": "ID Wallet de garde (par exemple, wal_ops_123)", "destinationWalletIdPlaceholder": "ID Wallet de destination", From b767d1018a723aeb8097a36c99ba2ccad64d174e Mon Sep 17 00:00:00 2001 From: Tomie <49788015+tomiet@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:15:31 -0600 Subject: [PATCH 5/6] fix(web): translate new counterparty playground strings in French Keep the fr payments catalog inventory-matched after upstream added playground hint placeholders. Co-authored-by: Cursor --- apps/sdp-web/messages/fr/dashboard-payments.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/sdp-web/messages/fr/dashboard-payments.json b/apps/sdp-web/messages/fr/dashboard-payments.json index 75c92c5b4..16d83e951 100644 --- a/apps/sdp-web/messages/fr/dashboard-payments.json +++ b/apps/sdp-web/messages/fr/dashboard-payments.json @@ -576,6 +576,10 @@ "getCounterparty": "Obtenez Counterparty", "createCounterparty": "Créer Counterparty", "playgroundEmailPlaceholder": "contact@acme.com", + "playgroundIndividualOnly": "Requis si entityType est individual ; laisser vide pour business.", + "playgroundAddressRequired": "Requis pour tous les types d'entité.", + "playgroundDateOfBirthPlaceholder": "1990-01-15", + "playgroundPhonePlaceholder": "+14155551234", "selectEntityType": "Sélectionnez le type d'entité", "updateCounterparty": "Mettre à jour Counterparty", "updatedDisplayNamePlaceholder": "Nom d'affichage mis à jour", From acd1dee51739ae86556379859d8a22340b032455 Mon Sep 17 00:00:00 2001 From: Gui Bibeau Date: Mon, 20 Jul 2026 17:10:32 -0400 Subject: [PATCH 6/6] fix(web): type-check French message catalogs --- apps/sdp-web/src/i18n/messages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sdp-web/src/i18n/messages.ts b/apps/sdp-web/src/i18n/messages.ts index eb41c7d76..1a1db8706 100644 --- a/apps/sdp-web/src/i18n/messages.ts +++ b/apps/sdp-web/src/i18n/messages.ts @@ -34,7 +34,7 @@ const frMessages = { ...frDashboardPayments, ...frDashboardPolicies, Shared: frShared, -} as Messages; +} satisfies Messages; export type MessageKeyFor = TValue extends string ? ""