{
	"api_kicker": "API développeur",
	"api_title": "Crée des activités depuis ton propre système",
	"api_intro": "Un POST par type d'activité. Envoie ton contenu en JSON et récupère une activité dans ton compte Puzzel.org, avec une URL à donner aux joueurs ou à glisser dans une iframe.",
	"api_search_placeholder": "Rechercher un point de terminaison, un champ ou un paramètre",
	"api_search_results": "correspondances sur cette page",
	"api_search_empty": "Rien sur cette page ne correspond. Essaie un nom de point de terminaison, un champ comme activity_key ou un code de statut.",
	"api_search_clear": "Effacer la recherche",
	"api_nav_guide": "Pour commencer",
	"api_nav_endpoints": "Points de terminaison",
	"api_toc_label": "Sur cette page",
	"api_hero_base_label": "URL de base",
	"api_hero_method_label": "Méthode",
	"api_hero_method_value": "POST, corps JSON",
	"api_hero_auth_label": "Auth",
	"api_hero_auth_value": "Clé + e-mail dans le corps",
	"api_hero_limit_label": "Quota",
	"api_hero_limit_value": "[limit] activités par jour",
	"api_hero_count_label": "Points de terminaison",
	"api_hero_count_value": "[count] types d'activités",
	"api_s_quickstart_title": "Ta première requête",
	"api_s_quickstart_body": "Rien à installer. Envoie une requête POST avec ta clé API, ton adresse e-mail et ton contenu dans le corps JSON. La réponse contient la clé de l'activité et son URL de jeu.",
	"api_s_quickstart_note": "Chaque exemple de cette page est une requête complète et exécutable. Remplace la clé et le contenu par les tiens et ça fonctionne tel quel.",
	"api_s_auth_title": "Authentification",
	"api_s_auth_body": "Aucun en-tête d'authentification ni jeton Bearer n'est nécessaire. La clé API et l'adresse e-mail figurent dans le corps JSON de chaque requête. Elles doivent correspondre au même compte.",
	"api_s_auth_where": "Ta clé se trouve dans la section compte de ton tableau de bord, derrière Afficher.",
	"api_s_auth_where_link": "Ouvrir ma clé API",
	"api_s_auth_premium": "Les clés API sont délivrées au démarrage d'un abonnement : un compte gratuit n'en a donc pas encore.",
	"api_s_auth_plans": "Voir les formules",
	"api_s_auth_secret": "Traite la clé comme un mot de passe. Elle crée et écrase des activités dans ton compte : garde-la côté serveur, hors de portée de tout ce qu'un navigateur peut lire.",
	"api_prefill_kicker": "Exemples",
	"api_prefill_label": "Remplir les exemples avec ma clé API",
	"api_prefill_signed_out": "Connecte-toi et ta clé s'insère dans tous les exemples de cette page.",
	"api_prefill_sign_in": "Se connecter",
	"api_prefill_none": "Pas encore de clé API sur ce compte.",
	"api_prefill_warning": "Chaque exemple contient maintenant ta vraie clé. N'en colle aucun dans un chat, un ticket ou un dépôt public.",
	"api_s_request_title": "Le corps de la requête",
	"api_s_request_body": "Tous les points de terminaison utilisent les cinq mêmes champs communs. Les champs de contenu varient selon l'activité : généralement un tableau d'éléments, parfois une phrase ou une image. Le sudoku ne nécessite aucun contenu supplémentaire.",
	"api_s_request_settings": "settings est un objet d'options propres à chaque point de terminaison. Celles qu'un point de terminaison lit sont listées avec lui ci-dessous ; tout le reste y est ignoré.",
	"api_col_field": "Champ",
	"api_col_type": "Type",
	"api_col_notes": "Rôle",
	"api_col_status": "Statut",
	"api_col_meaning": "Signification",
	"api_required": "obligatoire",
	"api_optional": "facultatif",
	"api_default_label": "Par défaut",
	"api_allowed_label": "Au choix",
	"api_in_settings": "dans settings",
	"api_f_account_api_key": "La clé API de ton compte. Elle va dans le corps, pas dans un en-tête.",
	"api_f_email": "L'adresse avec laquelle ton compte Puzzel.org se connecte. La clé n'est valide qu'avec elle.",
	"api_f_title": "Le nom de l'activité dans ton tableau de bord. Si tu ne renseignes pas ce champ, le point de terminaison utilise son titre par défaut.",
	"api_f_language": "Détermine seulement la langue dans l'URL renvoyée — rien de ce que tu envoies n'est traduit. Les mots mêlés le lisent aussi pour passer leurs lettres de remplissage à l'arabe quand il vaut \"ar\".",
	"api_f_activity_key": "Omets-le pour créer une nouvelle activité. Passe la clé d'une activité que tu possèdes déjà et c'est celle-ci qui est reconstruite.",
	"api_f_sentence_cryptogram": "La phrase à chiffrer. Les joueurs la décodent caractère par caractère.",
	"api_f_sentence_calculation": "La phrase que les joueurs découvrent en résolvant les calculs.",
	"api_f_image": "URL absolue de l'image à découper. Envoyée au premier niveau, pas dans settings.",
	"api_f_image_setting": "URL absolue de l'image à mélanger. Contrairement à celle du puzzle, celle-ci se place dans settings.",
	"api_s_response_title": "Ce qui est renvoyé",
	"api_s_response_body": "Un appel réussi répond 200 avec la clé de la nouvelle activité et l'URL où elle se joue. Tout le reste répond avec success à false et une seule chaîne error.",
	"api_response_success": "Succès",
	"api_response_error": "Échec",
	"api_s_response_urls": "L'url renvoyée est la vue intégrée. Remplace embed par play pour l'ouvrir en pleine page, ou par build pour l'ouvrir dans l'éditeur — la clé après p= ne change pas.",
	"api_s_updating_title": "Créer ou mettre à jour",
	"api_s_updating_body": "Envoie activity_key pour mettre à jour une activité existante. Son contenu est remplacé, son nom et son horodatage de version sont actualisés. Sa clé reste identique : les liens et les intégrations déjà partagés continuent de fonctionner. Les résultats, le dossier de rangement et les paramètres que le point de terminaison ne réécrit pas sont conservés.",
	"api_s_updating_own": "Tu ne peux mettre à jour que les activités appartenant à ton propre compte. La clé de quelqu'un d'autre répond 403.",
	"api_s_updating_name": "title est appliqué à chaque mise à jour. Si tu ne le fournis pas, l'activité est renommée avec le titre par défaut du point de terminaison.",
	"api_s_updating_settings": "Les blocs de paramètres qu'un point de terminaison écrit lui-même sont réécrits de zéro : une mise à jour les ramène donc aux valeurs que tu envoies, ou à celles par défaut du point de terminaison.",
	"api_s_updating_quota": "Une mise à jour coûte autant qu'une création : un appel sur le quota du jour.",
	"api_s_limits_title": "Limite de débit",
	"api_s_limits_body": "Chaque appel réussi compte, créations comme mises à jour. Dépasse la limite et la requête suivante répond 429 jusqu'à la remise à zéro du compteur.",
	"api_s_limits_counter": "[limit] activités par compte et par jour",
	"api_s_limits_reset": "Le compteur est remis à zéro une fois par jour par une tâche planifiée, et non sur une fenêtre glissante de 24 heures.",
	"api_s_errors_title": "Erreurs",
	"api_s_errors_body": "Les erreurs sont renvoyées en JSON avec les mêmes deux champs. Le champ error contient un message qui précise le champ ou la limite à l'origine du problème.",
	"api_err_400": "Quelque chose dans le corps manque, est mal formé ou hors limites. Le message nomme le champ.",
	"api_err_401": "L'e-mail est inconnu, ou la clé n'appartient pas à ce compte.",
	"api_err_403": "Le activity_key que tu as envoyé appartient à un autre compte.",
	"api_err_429": "Le quota du jour est épuisé. Il se réinitialise une fois par jour.",
	"api_err_500": "Le générateur n'a pas pu construire de casse-tête avec ce que tu as envoyé — en général trop peu de mots, ou des mots impossibles à assembler.",
	"api_endpoints_title": "Points de terminaison",
	"api_endpoints_intro": "Un chemin par type d'activité, tous en POST, tous sous la même URL de base. Chacun indique le contenu dont il a besoin, les paramètres qu'il lit et une requête que tu peux exécuter.",
	"api_group_words": "Mots et lettres",
	"api_group_cards": "Cartes et paires",
	"api_group_questions": "Questions et réponses",
	"api_group_text": "Phrases et nombres",
	"api_group_images": "Images",
	"api_ep_content_label": "Contenu",
	"api_ep_settings_label": "Paramètres lus",
	"api_ep_settings_none": "Ce point de terminaison ne lit aucun paramètre.",
	"api_ep_example_label": "Exemple de requête",
	"api_ep_notes_label": "Bon à savoir",
	"api_ep_min_items": "Au moins [count] dans items",
	"api_ep_no_items": "Ne prend pas d'items",
	"api_ep_default_title": "Nom de repli : “[title]”",
	"api_copy": "Copier",
	"api_copied": "Copié",
	"api_toast_copied": "Copié dans le presse-papiers",
	"api_ep_open_builder": "Ouvrir l'éditeur",
	"api_ep_back_to_top": "Retour en haut",
	"api_e_crossword": "Imbrique tes réponses dans une grille et numérote les définitions pour toi.",
	"api_c_crossword": "Un tableau de mots. Chaque entrée associe la réponse à la définition qui la désigne.",
	"api_note_crossword_length": "Les réponses de moins de deux caractères sont écartées avant la construction de la grille, et il faut qu'il en reste au moins deux.",
	"api_note_crossword_layout": "Les réponses sont mises en majuscules et le générateur dispose de vingt tentatives pour les placer. S'il n'arrive à placer aucun mot, l'appel répond 500.",
	"api_e_wordseeker": "Cache tes mots dans une grille de lettres, dans les directions et la forme de ton choix.",
	"api_c_wordseeker": "Un tableau de mots. Le texte de la définition devient la liste de mots à partir de laquelle les joueurs travaillent.",
	"api_note_wordseeker_length": "Les réponses de moins de deux caractères sont écartées, et chaque réponse est mise en majuscules avant d'entrer dans la grille.",
	"api_note_wordseeker_arabic": "La grille est complétée avec des lettres latines, sauf si language vaut \"ar\", ce qui bascule le remplissage en arabe.",
	"api_set_wordseeker_hidden_solution": "Les lettres restantes forment ce texte. Le définir indique aussi au générateur de placer la solution en premier plutôt que de caser un maximum de mots.",
	"api_set_wordseeker_directions": "Les sens dans lesquels un mot peut se lire. Omets-le et les mots vont uniquement vers l'est, le sud-est et le sud.",
	"api_set_wordseeker_template": "Découpe la grille en une forme au lieu de la laisser carrée.",
	"api_e_acrostic": "Empile tes réponses pour qu'une colonne forme un mot caché.",
	"api_c_acrostic": "Un tableau de mots. À eux tous, ils doivent fournir chaque lettre du mot caché.",
	"api_set_acrostic_hidden_solution": "Le mot que forme la colonne mise en évidence. Ce point de terminaison ne fonctionne pas sans lui.",
	"api_note_acrostic_letters": "Si les réponses ne peuvent pas fournir les lettres dont la solution a besoin, l'appel répond 500 plutôt que d'enregistrer une grille à moitié construite.",
	"api_note_acrostic_order": "Le générateur réordonne tes réponses pour que la colonne fonctionne : l'ordre que tu envoies n'est donc pas celui que voient les joueurs.",
	"api_e_word-scramble": "Mélange les lettres de chaque réponse, aux joueurs de les remettre en ordre.",
	"api_c_word-scramble": "Un tableau de mots. La définition s'affiche à côté des lettres mélangées.",
	"api_set_scramble_hidden_solution": "Un mot bonus facultatif que les joueurs saisissent une fois le reste résolu.",
	"api_note_scramble_random": "Les activités créées via l'API ont toujours le paramètre de mélange de l'ordre activé : l'ordre que tu envoies n'est donc pas celui que reçoivent les joueurs.",
	"api_e_hangman": "Transforme tes mots ou expressions en manches où l'on devine lettre par lettre.",
	"api_c_hangman": "Un tableau de mots ou d'expressions courtes. La définition est l'indice que voient les joueurs.",
	"api_e_wordle": "Fait un jeu de mot à deviner de chaque mot que tu envoies.",
	"api_c_wordle": "Un tableau de mots. Les joueurs ont une manche par mot.",
	"api_note_wordle_dictionary": "Créé avec le paramètre qui vérifie que les mots proposés existent vraiment. Désactive-le dans l'éditeur si tes mots sont des noms propres ou inventés.",
	"api_e_typing-practice": "Transforme des phrases en exercices de frappe.",
	"api_c_typing-practice": "Un tableau de mots ou de phrases à taper. Le champ de la définition sert aussi de consigne.",
	"api_e_wheel-of-fortune": "Remplit une roue avec tes propres segments.",
	"api_c_wheel-of-fortune": "Un tableau de segments. Chaque réponse devient une part.",
	"api_note_wheel_outcome": "Créé avec “afficher le résultat uniquement dans la roue” : le résultat se lit donc sur la roue au lieu d'être annoncé à côté.",
	"api_e_memory": "Des cartes face cachée à retourner pour former des paires.",
	"api_c_memory": "Un tableau de paires. Chaque paire contient les deux cartes qui vont ensemble.",
	"api_note_cards_media": "Une carte est un objet avec un champ type et un champ value. Utilise \"text\" pour des mots, ou \"image\", \"audio\", \"youtube\" ou \"link\" avec une URL dans value, et ajoute alt pour une description.",
	"api_e_matching-pairs": "Deux colonnes de cartes à rapprocher par glisser-déposer.",
	"api_c_matching-pairs": "Un tableau de paires de cartes. Les cartes de chaque paire sont placées de part et d'autre pour que les joueurs les associent.",
	"api_e_flash-cards": "Des cartes recto verso à faire défiler.",
	"api_c_flash-cards": "Un tableau de cartes. La première carte est le recto, la seconde le verso.",
	"api_note_flashcards_sides": "Le point de terminaison enregistre autant de cartes que tu en envoies : envoie-en donc exactement deux par entrée — le recto, puis le verso.",
	"api_e_categorize": "Des cartes à trier dans la catégorie à laquelle elles appartiennent.",
	"api_c_categorize": "Un tableau de catégories, chacune avec un nom et les cartes qui lui appartiennent.",
	"api_note_categorize_name": "Une catégorie envoyée sans nom est enregistrée sous “Untitled Category” : envoie-en donc toujours un.",
	"api_e_reorder": "Une séquence que les joueurs doivent remettre dans l'ordre.",
	"api_c_reorder": "Un tableau de séquences. Chacune contient ses cartes dans le bon ordre.",
	"api_note_reorder_order": "L'ordre que tu envoies est enregistré comme l'ordre correct — le numéro un en premier.",
	"api_e_quiz": "Des questions à choix multiple et des questions ouvertes, notées au fil du jeu.",
	"api_c_quiz": "Un tableau de questions. Les questions à choix multiple portent leurs réponses ; les questions ouvertes portent la réponse que tu acceptes.",
	"api_note_question_types": "question_type accepte \"multiple_choice\" ou \"open_answer\". Pour \"multiple_choice\", indique la bonne option avec isCorrect à true. Pour \"open_answer\", utilise correct_answer. Si question_type est absent, la question est traitée comme un choix multiple.",
	"api_note_quiz_settings": "Le point de terminaison quiz transmet settings tel quel sous forme de blocs de paramètres d'activité : ce n'est donc pas l'endroit pour des options en vrac — ajuste le quiz dans l'éditeur ensuite.",
	"api_e_board-game": "Un plateau à parcourir à toute vitesse, avec tes questions sur les cases.",
	"api_c_board-game": "Un tableau de questions, exactement la forme que prend le point de terminaison quiz.",
	"api_set_board_tiles": "Le nombre de cases du plateau. Entre 10 et 75.",
	"api_set_board_mode": "Si les joueurs foncent vers l'arrivée ou collectent des objets en chemin.",
	"api_e_cryptogram": "Transforme une phrase en un code à casser, un caractère à la fois.",
	"api_c_cryptogram": "Une phrase, dans le champ sentence. Ce point de terminaison ne prend pas d'items.",
	"api_note_cryptogram_no_items": "Tout ce que tu envoies dans items est ignoré — le casse-tête est construit à partir de la seule phrase.",
	"api_set_cryptogram_helpers": "Les caractères offerts d'emblée pour donner un point d'entrée : aucun, les plus fréquents, les voyelles, ou ceux que tu listes toi-même.",
	"api_set_cryptogram_character_list": "L'alphabet à partir duquel le chiffre est construit. Laissé vide, le chiffrement choisit le sien.",
	"api_set_cryptogram_extra_letters": "Les caractères offerts quand helpers vaut \"custom\". Ignoré pour les autres modes d'aide.",
	"api_set_cryptogram_hide_unused": "Laisse hors de la clé les caractères que la phrase n'utilise jamais.",
	"api_e_calculation": "Cache une phrase derrière des calculs — résous le calcul, révèle la lettre.",
	"api_c_calculation": "Une phrase, dans le champ sentence. Ce point de terminaison ne prend pas d'items.",
	"api_set_calc_difficulty": "Le résultat le plus élevé qu'un calcul peut avoir.",
	"api_set_calc_operators": "Les opérations autorisées. x correspond à la multiplication, : à la division.",
	"api_set_calc_max_operations": "Le nombre d'opérations qu'un même calcul peut enchaîner.",
	"api_set_calc_number_difficulty": "Plafonne les nombres à l'intérieur d'un calcul. De 5 à 1000, au choix.",
	"api_note_calculation_fit": "Si les contraintes sont trop strictes pour encoder la phrase, l'appel répond 400 en te demandant de les assouplir plutôt que d'enregistrer un casse-tête partiel.",
	"api_e_sudoku": "Génère une grille résolue, puis en retire des chiffres.",
	"api_c_sudoku": "Rien. Tout le casse-tête découle de ses deux paramètres.",
	"api_note_sudoku_no_items": "N'envoie ni items ni sentence — la taille et la difficulté sont toute l'entrée.",
	"api_note_sudoku_difficulty_sizes": "L'éditeur ne propose la difficulté que pour 2x3, 3x3 et 3x4. L'API l'applique à toutes les tailles, 2x2 et 4x4 compris.",
	"api_set_sudoku_size": "La taille d'un bloc, écrite en lignes par colonnes — 3x3 donne la grille classique 9x9. Le point de terminaison vérifie seulement que ça se lit comme deux nombres : reste donc sur les tailles proposées par l'éditeur.",
	"api_set_sudoku_difficulty": "Le nombre de chiffres laissés sur la grille au départ.",
	"api_e_jigsaw": "Découpe une image en pièces à rassembler par glisser-déposer.",
	"api_c_jigsaw": "Une URL d'image, dans le champ image. Ce point de terminaison ne prend pas d'items.",
	"api_note_jigsaw_grid": "L'API crée toujours un puzzle de 4 sur 4. Le nombre de pièces, les pièces irrégulières et les bords droits sont des paramètres de l'éditeur — envoyer rows ou columns ici ne fait rien.",
	"api_note_image_reachable": "L'URL est enregistrée telle que tu l'as envoyée et le fichier n'est jamais copié : elle doit donc rester accessible publiquement aussi longtemps que l'activité est jouée.",
	"api_e_slidingpuzzle": "Mélange une image en tuiles qui glissent jusqu'à leur place.",
	"api_c_slidingpuzzle": "Une URL d'image, dans settings. Ce point de terminaison ne prend pas d'items.",
	"api_note_sliding_image_slot": "Contrairement au puzzle, ce point de terminaison lit son image dans settings.image. Un champ image au premier niveau est ignoré et l'appel répond 400.",
	"api_help_title": "Quelque chose ne se comporte pas comme prévu ?",
	"api_help_body": "Envoie ta requête et le message d'erreur reçu. La personne qui a développé le point de terminaison te répondra directement.",
	"api_help_cta": "Écrire au support",
	"api_int_kicker": "Intégrations développeur",
	"api_int_title": "Connecte Puzzel à ta propre plateforme",
	"api_int_intro": "Puzzel peut transmettre directement le résultat d'un joueur à un autre système — son score, sa progression, ce qu'il a répondu — sans que ce système soit un LMS complet. Cette page recense tous les canaux disponibles : ce qui sort, quand ça sort, et le minimum à construire pour le récupérer.",
	"api_int_hero_out_label": "Les résultats sortent via",
	"api_int_hero_out_value": "Un webhook, ou un message vers la page qui héberge l'activité",
	"api_int_hero_in_label": "Ta page peut",
	"api_int_hero_in_value": "Connecter le joueur et réinitialiser l'activité",
	"api_int_hero_where_label": "Activé",
	"api_int_hero_where_value": "Par activité, dans le menu Développeur de l'éditeur",
	"api_int_hero_plan_label": "Inclus avec",
	"api_int_hero_plan_value": "Une formule payante — ces paramètres sont désactivés sur un compte gratuit",
	"api_int_search_placeholder": "Rechercher des canaux, des champs et des exemples",
	"api_int_search_empty": "Rien sur cette page ne correspond à ça. Essaie un canal comme webhook ou postMessage, ou un champ comme progress.",
	"api_int_nav_channels": "Canaux",
	"api_int_s_choose_title": "De quel canal as-tu besoin ?",
	"api_int_s_choose_body": "Trois choses peuvent sortir d'une activité et une seule peut y entrer. Le bon choix dépend d'une seule question : le joueur se trouve-t-il dans ta page, ou complètement ailleurs ?",
	"api_int_choose_out": "Hors de Puzzel",
	"api_int_choose_in": "Vers Puzzel",
	"api_int_choose_when": "À utiliser quand",
	"api_int_choose_needs": "Il te faut",
	"api_int_choose_setting": "Paramètre",
	"api_int_ch_webhook_name": "Webhook de résultats",
	"api_int_ch_webhook_summary": "Chaque résultat enregistré est envoyé en POST au format JSON vers une URL que tu possèdes.",
	"api_int_ch_webhook_when": "Le joueur peut être n'importe où — un lien partagé, un QR code, le site de quelqu'un d'autre — et tu veux le résultat dans ta propre base de données.",
	"api_int_ch_webhook_needs": "Un point de terminaison HTTPS qui accepte un POST cross-origin.",
	"api_int_ch_parent_name": "Résultats vers la page qui l'héberge",
	"api_int_ch_parent_summary": "Le même JSON, envoyé à la page qui intègre l'activité plutôt qu'à un serveur.",
	"api_int_ch_parent_when": "Tu intègres l'activité dans la page de ton propre cours et cette page peut elle-même exploiter le résultat.",
	"api_int_ch_parent_needs": "Un iframe sur ta page et un écouteur de messages. Pas de serveur, pas de CORS.",
	"api_int_ch_completion_name": "Signal de fin",
	"api_int_ch_completion_summary": "Un seul message quand le joueur termine, qui ne porte que cette information.",
	"api_int_ch_completion_when": "Tu veux seulement savoir s'il a terminé — pour cocher la leçon, débloquer la suivante, ou afficher ton propre écran.",
	"api_int_ch_completion_needs": "Un iframe sur ta page et un écouteur de messages.",
	"api_int_ch_trigger_name": "Réinitialisation depuis ta page",
	"api_int_ch_trigger_summary": "Ta page indique à l'activité intégrée d'effacer les réponses du joueur et de repartir de zéro.",
	"api_int_ch_trigger_when": "Tu as ton propre bouton \"réessayer\" en dehors de l'activité.",
	"api_int_ch_trigger_needs": "Un iframe sur ta page. Le message n'est accepté que depuis la page qui fait l'intégration.",
	"api_int_s_webhook_title": "Webhook de résultats",
	"api_int_s_webhook_body": "Active \"Envoyer les résultats à un webhook\" dans l'éditeur et indique une URL. À partir de là, chaque fois que la progression du joueur est enregistrée, son navigateur envoie l'ensemble du résultat en POST vers cette URL, au format JSON.",
	"api_int_webhook_steps_title": "Mise en place",
	"api_int_webhook_step_1": "Ouvre l'activité dans l'éditeur et va dans le menu Développeur.",
	"api_int_webhook_step_2": "Active \"Envoyer les résultats à un webhook\" et colle ton point de terminaison dans le champ juste en dessous. Ce doit être une URL complète — un simple domaine est refusé — et elle doit être en https, car le navigateur bloque un appel en http simple depuis une page servie en https.",
	"api_int_webhook_step_3": "Joue toi-même une fois à l'activité. Le premier POST arrive dès que tu réponds à quelque chose.",
	"api_int_webhook_receiver": "Un récepteur, de bout en bout",
	"api_int_webhook_timing_title": "Ça se déclenche pendant que tu joues, pas une seule fois à la fin",
	"api_int_webhook_timing_body": "Un résultat sort à chaque enregistrement de la saisie : après une pause dans la frappe, quand une carte est posée, quand le chronomètre s'arrête, et encore une fois quand l'activité est terminée. Une longue grille de mots croisés génère une vingtaine d'appels, pas un seul — écris donc ton gestionnaire comme un upsert indexé sur playerUid et activityKey plutôt que comme une insertion. Chaque appel transporte l'état complet, si bien que le plus récent remplace toujours le précédent et qu'un appel perdu est rattrapé par le suivant.",
	"api_int_webhook_finished_title": "Distinguer une fin d'un simple enregistrement",
	"api_int_webhook_finished_body": "progress est un pourcentage : 100 signifie que l'activité est terminée. Quelques types peuvent se terminer sans l'atteindre — un quiz entièrement répondu, un champ solution résolu — et portent alors hasAlternateCompletion à la place. Considère les deux cas comme terminés.",
	"api_int_webhook_cors_title": "C'est le navigateur du joueur qui l'envoie",
	"api_int_webhook_cors_body": "Le POST provient de l'onglet où l'activité est jouée, pas d'un serveur Puzzel. La plupart des points de terminaison conçus pour recevoir des webhooks l'acceptent déjà. Si le tien ne voit jamais de requête, voici pourquoi : le navigateur demande d'abord la permission, donc réponds au préflight OPTIONS avec un en-tête Access-Control-Allow-Origin et le vrai POST suivra.",
	"api_int_webhook_trust_title": "Traite le contenu comme une déclaration, pas comme une preuve",
	"api_int_webhook_trust_body": "La requête n'est pas signée et provient d'un navigateur que tu ne contrôles pas, donc n'importe qui regardant la page peut t'en envoyer une aussi. C'est sans risque pour remplir une barre de progression ou un tableau de bord. Pour tout ce que tu ne laisserais pas un élève régler lui-même — une note qui compte, un certificat, un paiement — vérifie-la par rapport aux résultats de ton propre tableau de bord Puzzel, ou laisse les connecteurs de notation LMS transmettre le score à ta place.",
	"api_int_s_parent_title": "Résultats vers la page qui l'héberge",
	"api_int_s_parent_body": "Si tu intègres l'activité, tu peux faire envoyer ce même JSON à ta propre page plutôt qu'à un serveur. Active \"Envoyer les résultats à la page parente\" et écoute le message. Rien ne sort du navigateur, donc aucun point de terminaison à construire et aucun CORS à gérer.",
	"api_int_parent_origin_title": "Vérifie la provenance du message",
	"api_int_parent_origin_body": "Ton écouteur reçoit tous les messages envoyés à la page, y compris depuis d'autres frames et des extensions de navigateur. Compare event.origin à https://puzzel.org avant de faire confiance à son contenu.",
	"api_int_parent_same_title": "Le même contenu, le même timing",
	"api_int_parent_same_body": "C'est le jumeau du webhook : les mêmes champs, envoyés aux mêmes moments. Tout ce qui est dit dans \"Ce que contient un résultat\" s'applique aussi ici.",
	"api_int_s_completion_title": "Signal de fin",
	"api_int_s_completion_body": "Le plus petit canal, pour quand le résultat lui-même ne te regarde pas : active \"Envoyer un signal de fin\" et ta page reçoit un message dès que le joueur termine.",
	"api_int_completion_shape": "Ce qui arrive",
	"api_int_completion_order_title": "Le résultat est déjà enregistré quand il arrive",
	"api_int_completion_order_body": "Le signal est volontairement envoyé après que l'enregistrement final a eu lieu, donc une page qui réagit en relisant le résultat le trouvera bien là.",
	"api_int_completion_embed_title": "Uniquement dans un iframe",
	"api_int_completion_embed_body": "Les deux canaux de messages envoient à la page qui encadre l'activité. Ouverte dans son propre onglet, il n'y a personne à prévenir, donc rien n'est envoyé.",
	"api_int_s_payload_title": "Ce que contient un résultat",
	"api_int_s_payload_body": "Une seule structure, quel que soit le canal qui la transporte. Les réponses du joueur sont indexées par les identifiants propres des éléments de l'activité, donc les mêmes clés se retrouvent dans correctUids.",
	"api_int_col_when": "Quand c'est présent",
	"api_int_always": "toujours",
	"api_int_sometimes": "parfois",
	"api_int_payload_absent_title": "Absent, pas vide",
	"api_int_payload_absent_body": "Un champ qui ne s'applique pas est omis du JSON plutôt qu'envoyé comme null ou zéro. C'est ainsi qu'on distingue un type qui ne note pas une partie d'une partie qui a obtenu un score nul — lis donc avec une valeur par défaut et ne suppose jamais qu'une clé est présente.",
	"api_int_payload_example": "Un quiz terminé, tel qu'il arrive",
	"api_int_f_activity_key": "L'activité à laquelle appartient le résultat. La même clé que celle affichée dans l'URL de l'activité, après ?p=.",
	"api_int_f_player_uid": "Qui a joué, sous forme d'identifiant anonyme. Stable pour ce joueur sur cet appareil, c'est donc sur cette valeur qu'il faut indexer les résultats — ce n'est ni une adresse e-mail ni un compte Puzzel.",
	"api_int_f_player": "Les champs d'inscription demandés par l'activité, tels que tu les as configurés : name, email, class, student_id, etc. Absent tant que le joueur ne s'est pas inscrit, et absent entièrement sur une activité qui ne demande rien.",
	"api_int_f_progress": "La progression, en pourcentage. 100 signifie terminé.",
	"api_int_f_time_passed": "Temps passé sur l'activité, en millisecondes.",
	"api_int_f_last_played_at": "Quand ce résultat a été enregistré, sous forme d'horodatage Unix en millisecondes.",
	"api_int_f_created": "Quand la tentative a commencé, sous forme d'horodatage Unix en millisecondes.",
	"api_int_f_player_input": "Ce que le joueur a réellement saisi, indexé par l'identifiant de l'élément auquel ça appartient. La structure interne dépend du type d'activité — un mot, une liste de cartes placées, une option choisie.",
	"api_int_f_correct_uids": "Lesquels de ces éléments sont corrects, indexés de la même façon. Absent tant qu'aucune réponse n'a encore été donnée.",
	"api_int_f_score": "Points obtenus, sur les types qui notent une partie. Absent partout ailleurs — y compris sur une partie qui a réellement obtenu un score nul, donc vérifie que la clé existe avant de la lire.",
	"api_int_f_performance": "La mesure propre à un type pour évaluer sa performance, quand il en garde une — le nombre de mots par minute pour l'entraînement au clavier, par exemple.",
	"api_int_f_attempts": "Le numéro de cette partie : 1 la première fois, un de plus à chaque nouveau départ. Uniquement sur les types qui peuvent arrêter une partie avant la fin et qui comptent les tentatives.",
	"api_int_f_knocked_out": "La partie s'est terminée sur une mauvaise réponse et est finie sans être complète.",
	"api_int_f_alternate": "L'activité a été terminée d'une façon qui n'atteint pas 100 % — un quiz entièrement répondu, un champ solution résolu. Considère cela comme une fin d'activité.",
	"api_int_f_missed_keys": "Les caractères que le joueur a le plus souvent mal saisis, du plus manqué au moins manqué. Uniquement pour l'entraînement au clavier.",
	"api_int_f_content_version": "La version du contenu de l'activité sur laquelle cela a été joué. Elle change quand le propriétaire modifie les questions, ce qui permet de distinguer un ancien résultat d'un résultat actuel.",
	"api_int_s_control_title": "Réinitialiser l'activité depuis ta page",
	"api_int_s_control_body": "Une instruction circule dans l'autre sens. Avec \"Accepter les commandes de la page parente\" activé, la page qui fait l'intégration peut effacer les réponses du joueur et remettre l'activité à son point de départ — pour ton propre bouton \"réessayer\", en dehors du cadre.",
	"api_int_control_only_title": "La réinitialisation est la seule commande possible",
	"api_int_control_only_body": "Il n'existe aucun message pour soumettre un résultat, ouvrir le message de fin ou sauter à une question. Un message demandant autre chose qu'une réinitialisation est ignoré.",
	"api_int_control_guard_title": "Seule la page qui intègre l'activité est écoutée",
	"api_int_control_guard_body": "La commande n'est acceptée que depuis la page qui encadre l'activité, et de nulle part ailleurs — ni une frame voisine, ni un script sur la page. Le paramètre est désactivé par défaut, active-le donc pour les activités que tu pilotes.",
	"api_int_s_identity_title": "Utiliser ta propre identité de joueur",
	"api_int_s_identity_body": "Si ta plateforme sait déjà qui joue, l'activité n'a pas besoin de le redemander. Deux échanges existent, tous deux pour une activité intégrée dans ta page, et tous deux activés par nous plutôt que dans l'éditeur — ils déterminent à qui appartient un résultat, donc ils se mettent en place avec toi plutôt que depuis une case à cocher.",
	"api_int_identity_pm_title": "Poste-nous le joueur",
	"api_int_identity_pm_body": "L'activité s'annonce avec 'app-loaded' et attend. Ta page renvoie les informations du joueur, et le résultat est classé sous son nom sans qu'il ait à saisir quoi que ce soit ni à voir un écran d'inscription.",
	"api_int_identity_sso_title": "Poste-nous un jeton",
	"api_int_identity_sso_body": "Le même échange, mais ta page poste le JWT émis par ton fournisseur d'identité plutôt que les champs eux-mêmes. Nous le vérifions par rapport aux émetteurs configurés pour ton compte avant de laisser entrer le joueur, ce qui prouve l'identité au lieu de la déclarer simplement — c'est celui-ci qu'il faut demander quand le résultat doit être fiable.",
	"api_int_identity_cta_title": "Demande-nous de l'activer",
	"api_int_identity_cta_body": "Dis-nous lequel des deux tu souhaites et où les activités seront intégrées, et nous configurerons ton compte et t'accompagnerons pas à pas.",
	"api_int_identity_cta_button": "Nous écrire à propos de l'identité",
	"api_int_s_create_title": "Créer des activités depuis ton système",
	"api_int_s_create_body": "Tout ce qui précède concerne un résultat qui sort. Faire l'inverse — créer les activités elles-mêmes à partir de contenu que tu possèdes déjà — c'est le rôle de la Puzzle API : un POST par type d'activité, et tu récupères une clé et une URL à intégrer.",
	"api_int_create_link": "Lire la référence de l'API",
	"api_int_s_lms_title": "Quand un connecteur tout prêt est la meilleure solution",
	"api_int_s_lms_body": "Si la plateforme en face est un vrai LMS, tu n'as probablement besoin de rien de tout ça. Les notes peuvent remonter d'elles-mêmes dans son carnet de notes, sans rien à héberger de ton côté.",
	"api_int_lms_lti_title": "Moodle, Canvas, Brightspace, Schoology, itslearning",
	"api_int_lms_lti_body": "Lancée depuis le LMS, avec le score renvoyé dans son carnet de notes.",
	"api_int_lms_gc_title": "Google Classroom",
	"api_int_lms_gc_body": "Publie une activité comme un devoir et récupère les notes automatiquement.",
	"api_int_lms_not_title": "Aucun de ceux-là ?",
	"api_int_lms_not_body": "Les plateformes de cours, les sites à abonnement, les intranets et tout ce que tu as construit toi-même sont exactement ce à quoi servent les canaux de cette page. Une intégration associée au signal de fin couvre la plupart des cas.",
	"api_int_s_limits_title": "Ce qu'il n'y a pas",
	"api_int_s_limits_body": "Pour que tu ne le cherches pas en vain :",
	"api_int_limit_no_read": "Aucun point de terminaison pour relire les résultats. L'API crée des activités ; les résultats sortent par les canaux de cette page, ou par les exports de ton tableau de bord.",
	"api_int_limit_no_signature": "Aucune signature sur le webhook. Il n'y a rien pour vérifier la requête, c'est pourquoi un résultat ne devrait jamais être la seule chose garantissant quelque chose d'important.",
	"api_int_limit_per_activity": "Aucun webhook valable pour tout le compte. L'URL est un paramètre de l'activité, donc une activité copiée l'emporte avec elle et une nouvelle activité démarre sans.",
	"api_int_limit_no_multiplayer": "Rien dans un jeu en équipes ou une salle en direct. Les deux canaux de messages et le webhook sont réservés au jeu en solo, et les paramètres se désactivent d'eux-mêmes quand le mode équipes est actif.",
	"api_int_limit_no_retry": "Aucune file d'attente de livraison. Rien n'est stocké puis renvoyé — le prochain enregistrement fait office de nouvelle tentative, et c'est le dernier appel de la partie qui compte.",
	"api_nav_integrations": "Récupérer les résultats"
}
