```
✨ feat(security): Ajoute réinitialisation mot de passe, robots.txt, et traductions.
Ajoute la fonctionnalité de réinitialisation de mot de passe, met à jour le
robots.txt, et ajoute des traductions en français et en anglais.
```
This commit is contained in:
@@ -40,10 +40,9 @@ security:
|
||||
# algorithm: bcrypt
|
||||
|
||||
role_hierarchy:
|
||||
ROLE_ADMIN: [ROLE_ARTEMIS]
|
||||
ROLE_ROOT: [ROLE_ADMIN] # ROLE_ROOT inclut ROLE_ADMIN, qui à son tour inclut ROLE_ARTEMIS
|
||||
|
||||
|
||||
access_control:
|
||||
- { path: ^/artemis, roles: [ROLE_ARTEMIS,ROLE_CUSTOMER] }
|
||||
- { path: ^/admin, roles: [ROLE_ADMIN] }
|
||||
- { path: ^/, roles: PUBLIC_ACCESS } # Toutes les autres pages nécessitent une authentification complète
|
||||
|
||||
@@ -44,6 +44,11 @@ class SecurityController extends AbstractController
|
||||
return $this->render('security/forgot_password.twig', [
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/logout', name: 'app_logout', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function logout(): Response
|
||||
{
|
||||
|
||||
}
|
||||
#[Route(path: '/mot-de-passe-oublie/sent', name: 'app_forgot_password_sent', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function forgotPasswordSent(Request $request,EventDispatcherInterface $eventDispatcher): Response
|
||||
@@ -52,8 +57,49 @@ class SecurityController extends AbstractController
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/mot-de-passe-oublie/{id}/{token}', name: 'app_forgot_password_confirm', options: ['sitemap' => false], methods: ['GET','POST'])]
|
||||
public function forgotPasswordConfirm(Request $request): Response
|
||||
public function forgotPasswordConfirm(UserPasswordHasherInterface $userPasswordHasher,EventDispatcherInterface $eventDispatcher,Request $request,EntityManagerInterface $entityManager,string $id,string $token): Response
|
||||
{
|
||||
$errorMessage = "Requête non valide.";
|
||||
if (!is_numeric($id)) {
|
||||
$this->addFlash("error", $errorMessage);
|
||||
return $this->redirectToRoute('app_forgot_password');
|
||||
}
|
||||
$account = $entityManager->getRepository(Account::class)->find((int)$id);
|
||||
if (!$account instanceof Account) {
|
||||
$this->addFlash("error", $errorMessage);
|
||||
return $this->redirectToRoute('app_forgot_password');
|
||||
}
|
||||
$requestToken = $entityManager->getRepository(AccountResetPasswordRequest::class)->findOneBy([
|
||||
'Account' => $account, // Assurez-vous que 'Account' est le nom correct de la propriété/colonne dans votre entité AccountResetPasswordRequest.
|
||||
'token' => $token
|
||||
]);
|
||||
if (!$requestToken instanceof AccountResetPasswordRequest) {
|
||||
$this->addFlash("error", $errorMessage);
|
||||
return $this->redirectToRoute('app_forgot_password');
|
||||
}
|
||||
$now = new \DateTimeImmutable();
|
||||
if ($requestToken->getExpiresAt() < $now) {
|
||||
$this->addFlash("error", "Le lien de réinitialisation de mot de passe a expiré.");
|
||||
return $this->redirectToRoute('app_forgot_password');
|
||||
}
|
||||
|
||||
$event = new ResetPasswordConfirmEvent();
|
||||
$form = $this->createForm(RequestPasswordConfirmType::class,$event);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$account->setPassword($userPasswordHasher->hashPassword($account,$event->getPassword()));
|
||||
$entityManager->persist($account);
|
||||
$entityManager->flush();
|
||||
$this->addFlash("success", "Votre mot de passe a été mis à jour avec succès.");
|
||||
return $this->redirectToRoute('app_login');
|
||||
}
|
||||
return $this->render('security/forgot-password-confirm.twig', [
|
||||
'form' => $form->createView(),
|
||||
'noIndex' => true,
|
||||
'id' => $id,
|
||||
'token' => $token,
|
||||
'account' => $account,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@ class SeoController extends AbstractController
|
||||
$robots->addDisallow($this->generateUrl('app_cookies'));
|
||||
$robots->addDisallow($this->generateUrl('app_cgu'));
|
||||
$robots->addDisallow($this->generateUrl('app_cgv'));
|
||||
$robots->addDisallow($this->generateUrl('app_login'));
|
||||
$robots->addDisallow($this->generateUrl('app_logout'));
|
||||
$robots->addDisallow($this->generateUrl('app_forgot_password'));
|
||||
|
||||
$robots->addSpacer();
|
||||
$robots->addComment("Sitemap");
|
||||
|
||||
@@ -68,11 +68,10 @@ class ResetPasswordSubscriber
|
||||
UrlGeneratorInterface::ABSOLUTE_URL
|
||||
);
|
||||
|
||||
$title = "[E-Cosplay]";
|
||||
$this->mailer->send(
|
||||
$account->getEmail(),
|
||||
$account->getUsername(),
|
||||
' - Lien pour réinitialiser votre mot de passe',
|
||||
'[E-Cosplay] - Lien pour réinitialiser votre mot de passe',
|
||||
'mails/reset.twig',
|
||||
[
|
||||
'account' => $account,
|
||||
|
||||
28
templates/mails/reset.twig
Normal file
28
templates/mails/reset.twig
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends 'mails/base.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<mj-text>Bonjour, </mj-text>
|
||||
|
||||
{% if 'ROLE_CUSTOMER' in datas.account.roles %}
|
||||
<mj-text>Nous avons reçu une demande de réinitialisation de mot de passe pour votre espace client.</mj-text>
|
||||
{% else %}
|
||||
<mj-text>Nous avons reçu une demande de réinitialisation de mot de passe pour votre compte E-Cosplay.</mj-text>
|
||||
{% endif %}
|
||||
|
||||
<mj-text>Pour réinitialiser votre mot de passe, veuillez cliquer sur le bouton ci-dessous. Ce lien est valable pour une durée limitée.</mj-text>
|
||||
|
||||
<mj-button href="{{ datas.resetLink }}">
|
||||
Réinitialiser mon mot de passe
|
||||
</mj-button>
|
||||
|
||||
<mj-text padding-top="20px">
|
||||
Ce lien expirera le {{ datas.request.expiresAt|date('d/m/Y à H:i') }}.
|
||||
<br/>
|
||||
Veuillez l'utiliser avant cette date et heure.
|
||||
</mj-text>
|
||||
|
||||
<mj-text>Si vous n'avez pas demandé cette réinitialisation de mot de passe, veuillez ignorer cet e-mail. Votre mot de passe actuel restera inchangé.</mj-text>
|
||||
|
||||
<mj-text padding-top="20px">Cordialement,</mj-text>
|
||||
<mj-text>L'équipe E-Cosplay</mj-text>
|
||||
{% endblock %}
|
||||
100
templates/security/forgot-password-confirm.twig
Normal file
100
templates/security/forgot-password-confirm.twig
Normal file
@@ -0,0 +1,100 @@
|
||||
{% extends 'base.twig' %}
|
||||
|
||||
{% block title %}{{ 'events.reset_password'|trans }}{% endblock %}
|
||||
{% block meta_description %}{{ 'events.reset_password'|trans }}{% endblock %}
|
||||
|
||||
{% block canonical_url %}<link rel="canonical" href="{{ url('app_forgot_password_confirm', {id: id, token: token}) }}" />{% endblock %}
|
||||
{% block breadcrumb_schema %}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 1,
|
||||
"name": "{{ 'breadcrumb.home'|trans }}",
|
||||
"item": "{{ app.request.schemeAndHttpHost }}"
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 2,
|
||||
"name": "{{ 'breadcrumb.reset_password'|trans }}",
|
||||
"item": "{{ app.request.schemeAndHttpHost }}{{ app.request.pathInfo }}"
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-md w-full space-y-8 p-10 bg-white rounded-xl shadow-lg">
|
||||
|
||||
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
|
||||
{{ 'events.reset_password'|trans }}
|
||||
</h2>
|
||||
|
||||
<p class="mt-2 text-center text-sm text-gray-600">
|
||||
{{ 'text.enter_new_password'|trans }}
|
||||
</p>
|
||||
|
||||
{# Affichage des messages flash (ex: token expiré ou invalide) #}
|
||||
{% for flash_error in app.flashes('reset_password_error') %}
|
||||
<div class="p-4 text-sm text-red-700 bg-red-100 rounded-lg" role="alert">
|
||||
{{ flash_error }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{# Le formulaire Symfony #}
|
||||
{{ form_start(form, {'attr': {'class': 'mt-8 space-y-6'}}) }}
|
||||
|
||||
<div class="rounded-md shadow-sm -space-y-px">
|
||||
{# Champ Nouveau Mot de Passe (first) #}
|
||||
{# On suppose que form.plainPassword est un RepeatedType avec un champ 'first' et 'second' #}
|
||||
|
||||
<div>
|
||||
{{ form_label(form.password.first, 'label.new_password'|trans, {'label_attr': {'class': 'sr-only'}}) }}
|
||||
{{ form_widget(form.password.first, {
|
||||
'attr': {
|
||||
'class': 'appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm',
|
||||
'placeholder': 'label.new_password'|trans,
|
||||
'autocomplete': 'new-password',
|
||||
'required': 'required'
|
||||
}
|
||||
}) }}
|
||||
{{ form_errors(form.password.first) }}
|
||||
</div>
|
||||
|
||||
{# Champ Confirmation Mot de Passe (second) #}
|
||||
<div>
|
||||
{{ form_label(form.password.second, 'label.confirm_password'|trans, {'label_attr': {'class': 'sr-only'}}) }}
|
||||
{{ form_widget(form.password.second, {
|
||||
'attr': {
|
||||
'class': 'appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm',
|
||||
'placeholder': 'label.confirm_password'|trans,
|
||||
'autocomplete': 'new-password',
|
||||
'required': 'required'
|
||||
}
|
||||
}) }}
|
||||
{{ form_errors(form.password.second) }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{# Affichage des erreurs globales du formulaire #}
|
||||
{{ form_errors(form) }}
|
||||
|
||||
{# Bouton Soumettre #}
|
||||
<div>
|
||||
<button type="submit"
|
||||
class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
||||
{{ 'button.reset_password'|trans }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{ form_end(form) }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends 'base.twig' %}
|
||||
|
||||
{% block title %}{{ 'events.login'|trans }}{% endblock %}
|
||||
{% block meta_description %}{{ 'events.login'|trans }}{% endblock %}
|
||||
{% block title %}{{ 'page.login'|trans }}{% endblock %}
|
||||
{% block meta_description %}{{ 'page.login'|trans }}{% endblock %}
|
||||
|
||||
{% block canonical_url %}<link rel="canonical" href="{{ url('app_login') }}" />{% endblock %}
|
||||
{% block breadcrumb_schema %}
|
||||
@@ -38,10 +38,14 @@
|
||||
{# Display error messages if login fails #}
|
||||
{% if error %}
|
||||
<div class="p-4 mb-4 text-sm text-red-700 bg-red-100 rounded-lg" role="alert">
|
||||
<span class="font-medium">{{ 'error.login_failed'|trans }}</span> {{ error.messageKey|trans(error.arguments, 'security') }}
|
||||
{{ dump(error) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% for message in app.flashes('success') %}
|
||||
<div class="p-4 text-sm text-green-700 bg-green-100 rounded-lg" role="alert">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{# The actual login form #}
|
||||
<form class="mt-8 space-y-6" action="{{ path('app_login') }}" method="post">
|
||||
<input type="hidden" name="remember" value="true">
|
||||
|
||||
@@ -536,34 +536,34 @@ events.list_main_title: Events
|
||||
events.no_events_title: No Planned Events
|
||||
events.no_events_message: It seems there are no planned events for the moment. Check back soon!
|
||||
events.button_contact: Contact Us
|
||||
|
||||
events.login: Login
|
||||
login_link: Log In
|
||||
register_link: Register
|
||||
|
||||
# translations/messages.en.yaml
|
||||
|
||||
# Login Page (Connexion)
|
||||
events.login: Login
|
||||
events.forgot_password: Forgot Password
|
||||
|
||||
# Breadcrumbs
|
||||
breadcrumb.login: Login
|
||||
breadcrumb.forgot_password: Forgot Password
|
||||
|
||||
# Labels and Buttons
|
||||
breadcrumb.login: Log In
|
||||
label.email: Email address
|
||||
label.password: Password
|
||||
label.remember_me: Remember me
|
||||
button.sign_in: Sign In
|
||||
button.send_reset_link: Send Reset Link
|
||||
|
||||
# Links
|
||||
link.forgot_password: Forgot your password?
|
||||
link.back_to_login: Back to login
|
||||
|
||||
# Errors and Security Messages
|
||||
link.forgot_password: Forgot password?
|
||||
error.login_failed: Login failed.
|
||||
|
||||
security.login: Sign in to your account
|
||||
|
||||
# Descriptive text
|
||||
security.login: Log in to your account
|
||||
events.forgot_password: Forgot Password
|
||||
breadcrumb.forgot_password: Forgot Password
|
||||
text.enter_email_for_reset: Please enter your email address to receive a reset link.
|
||||
button.send_reset_link: Send Reset Link
|
||||
link.back_to_login: Back to Log In
|
||||
events.reset_email_sent: Reset Email Sent
|
||||
text.check_inbox_title: Check your inbox 📥
|
||||
text.check_inbox_description: An email has been sent with a link to reset your password. It may arrive in a few minutes.
|
||||
text.spam_folder_tip: If you don't see it, check your spam folder.
|
||||
events.reset_password: Reset Password
|
||||
breadcrumb.reset_password: Password Reset
|
||||
label.new_password: New password
|
||||
label.confirm_password: Confirm new password
|
||||
text.enter_new_password: Please enter and confirm your new password.
|
||||
button.reset_password: Reset Password
|
||||
open_user_menu_sr: Open user menu
|
||||
logged_in_as: Signed in as
|
||||
logout_link: Log Out
|
||||
page.login: Login
|
||||
|
||||
@@ -309,12 +309,8 @@ legal_section8_p1_law: Tout litige en relation avec l’utilisation du site %sit
|
||||
rgpd_short_title: Politique RGPD
|
||||
rgpd_page_title: Politique de Confidentialité (RGPD)
|
||||
rgpd_page_title_long: Politique de Confidentialité et RGPD
|
||||
|
||||
# Section 1 : Engagement
|
||||
rgpd_section1_title: 1. Engagement de l'Association E-Cosplay
|
||||
rgpd_section1_p1: L'association E-Cosplay s'engage à respecter la vie privée de ses utilisateurs et à traiter leurs données personnelles en toute transparence et conformément au Règlement Général sur la Protection des Données (RGPD).
|
||||
|
||||
# Section 2 : Données Collectées
|
||||
rgpd_section2_title: 2. Données Personnelles Collectées et Finalité
|
||||
rgpd_section2_p1_commitment: L'association E-Cosplay adopte une politique de collecte de données strictement minimale.
|
||||
rgpd_section2_p2_data_collected: "Nous ne collectons aucune information superflue ou de surplus. Les seules données personnelles recueillies sur ce site le sont dans le cadre précis du :"
|
||||
@@ -324,8 +320,6 @@ rgpd_contest_form_title: Fiches d'inscription aux concours
|
||||
rgpd_contest_form_details: Dans le cadre des concours cosplay, nous collectons les données nécessaires à l'inscription, incluant des fichiers média (audio, image, vidéo) soumis par les participants pour l'évaluation. Ces données sont soumises à la même rigueur de traitement que toutes les autres informations personnelles.
|
||||
rgpd_no_other_collection_title: Absence d'autres collectes
|
||||
rgpd_no_other_collection_details: Aucune autre donnée n'est collectée automatiquement ou indirectement à des fins de profilage ou de traçage.
|
||||
|
||||
# Section 3 : Confidentialité et Sécurité
|
||||
rgpd_section3_title: 3. Confidentialité et Sécurité des Données
|
||||
rgpd_section3_subtitle1: Non-Revente des Données
|
||||
rgpd_section3_p1_no_resale: L'association E-Cosplay ne revend, ne loue et ne met à disposition sous aucune forme les données personnelles collectées à des tiers, à des fins commerciales ou autres. Vos données sont traitées en interne et restent confidentielles.
|
||||
@@ -345,8 +339,6 @@ rgpd_breach_list2_strong: Déclaration aux Autorités
|
||||
rgpd_breach_list2_details: Une déclaration sera effectuée auprès de la CNIL (Commission Nationale de l'Informatique et des Libertés) et de l'ANSSI (Agence Nationale de la Sécurité des Systèmes d'Information) dans un délai maximum de 24 heures après la découverte de la violation.
|
||||
rgpd_breach_list3_strong: Transparence Complète
|
||||
rgpd_breach_list3_details: Une communication transparente et complète sera mise en place concernant la nature de la violation, les données potentiellement affectées, et les mesures prises pour y remédier.
|
||||
|
||||
# Section 4 : Durée de Conservation
|
||||
rgpd_section4_title: 4. Durée de Conservation et Suppression Automatique
|
||||
rgpd_section4_subtitle1: Données d'Inscription aux Concours
|
||||
rgpd_section4_p1_contest_data_intro: "Les données spécifiques collectées pour les concours (fiche d'inscription, fichiers audio/image/vidéo, ordre de passage, notations des juges) sont conservées pendant une durée limitée :"
|
||||
@@ -365,8 +357,6 @@ rgpd_section4_p3_general_deletion: Pour assurer un nettoyage régulier, toutes l
|
||||
rgpd_section4_subtitle4: Autres Données
|
||||
rgpd_section4_p4_other_data: Les données du formulaire de contact sont conservées uniquement le temps de traiter la demande, puis supprimées automatiquement après un délai raisonnable de suivi (maximum 6 mois).
|
||||
rgpd_section4_p5_rights_reminder: Vous conservez à tout moment votre droit de demander la suppression anticipée de vos données (voir Section 5).
|
||||
|
||||
# Section 5 : Vos Droits
|
||||
rgpd_section5_title: 5. Vos Droits (Droit d'Accès, de Rectification et de Suppression)
|
||||
rgpd_section5_p1_rights_intro: "Conformément au RGPD, vous disposez des droits suivants concernant vos données :"
|
||||
rgpd_right_access: Droit d'accès (savoir quelles données sont conservées).
|
||||
@@ -374,16 +364,12 @@ rgpd_right_rectification: Droit de rectification (modifier des données erronée
|
||||
rgpd_right_erasure: Droit à l'effacement ou "droit à l'oubli" (demander la suppression de vos données).
|
||||
rgpd_right_opposition: Droit d'opposition et de limitation du traitement.
|
||||
rgpd_section5_p2_contact_dpo: "Pour exercer ces droits, vous pouvez contacter notre Délégué à la Protection des Données (DPO) :"
|
||||
|
||||
# --- Navigation & Menu ---
|
||||
Accueil: "Accueil"
|
||||
Qui sommes-nous: "Qui sommes-nous"
|
||||
Nos membres: "Nos membres"
|
||||
Nos événements: "Nos événements"
|
||||
Contact: "Contact"
|
||||
open_main_menu_sr: "Ouvrir le menu principal"
|
||||
|
||||
# --- Panier (Off-Canvas Cart) ---
|
||||
open_cart_sr: "Ouvrir le panier"
|
||||
your_cart: "Votre Panier"
|
||||
close_cart_sr: "Fermer le panier"
|
||||
@@ -391,8 +377,6 @@ cart_empty: "Votre panier est vide."
|
||||
subtotal_label: "Sous-total"
|
||||
checkout_button: "Passer à la caisse"
|
||||
shipping_disclaimer: "Frais de port calculés à l'étape suivante."
|
||||
|
||||
# --- Footer ---
|
||||
footer_contact_title: "Nous Contacter"
|
||||
footer_follow_us_title: "Nous Suivre"
|
||||
footer_mission_description: |
|
||||
@@ -401,39 +385,25 @@ footer_mission_description: |
|
||||
une plateforme pour les passionnés et de mettre en avant le talent créatif.
|
||||
all_rights_reserved: "Tous droits réservés"
|
||||
association_status: "Association loi 1901 à but non lucratif."
|
||||
|
||||
# --- Liens Légaux ---
|
||||
legal_notice_link: "Mentions Légales"
|
||||
cookie_policy_link: "Politique de Cookies"
|
||||
hosting_link: "Hébergement"
|
||||
rgpd_policy_link: "Politique RGPD"
|
||||
cgu_link: "CGU"
|
||||
cgv_link: "CGV"
|
||||
|
||||
|
||||
# --- Formulaire de Contact (Keys) ---
|
||||
# TITRES DE PAGE ET BREADCRUMBS
|
||||
contact_page.title: "Contactez Nous"
|
||||
contact_page.breadcrumb: "Contactez Nous"
|
||||
breadcrumb.home: "Accueil"
|
||||
|
||||
# MESSAGES FLASH
|
||||
flash.success.strong: "Message envoyé !"
|
||||
flash.error.strong: "Message Erreur !"
|
||||
|
||||
# INFORMATIONS DE CONTACT (COLONNE DE GAUCHE)
|
||||
contact_info.title: "Restons Connectés"
|
||||
contact_info.subtitle: "Que ce soit pour une question technique, une opportunité de partenariat ou une simple salutation, nous sommes là pour vous."
|
||||
contact_info.email: "E-mail"
|
||||
contact_info.address: "Adresse Postale"
|
||||
contact_info.join_title: "Rejoindre l'association"
|
||||
contact_info.join_text: "Vous souhaitez nous rejoindre ou obtenir plus d'informations sur les modalités d'adhésion ? Veuillez nous écrire directement à :"
|
||||
|
||||
# FORMULAIRE (COLONNE DE DROITE)
|
||||
form.title: "Envoyez-nous un Message"
|
||||
form.submit_button: "Envoyer le message"
|
||||
|
||||
# CLÉS DU FORMULAIRE (celles de votre premier message)
|
||||
contact_form.name.label: "Prénom"
|
||||
contact_form.surname.label: "Nom de famille"
|
||||
contact_form.subject.label: "Sujet"
|
||||
@@ -446,7 +416,6 @@ contact_form.subject.placeholder: "Objet de votre message"
|
||||
contact_form.email.placeholder: "votre.email@exemple.com"
|
||||
contact_form.surname.placeholder: "Votre nom de famille"
|
||||
contact_form.name.placeholder: "Votre prénom"
|
||||
|
||||
members_page.title: "Nos Membres & Bureau"
|
||||
members_page.breadcrumb: "Membres"
|
||||
members_page.board_title: "Membres du Bureau"
|
||||
@@ -454,7 +423,6 @@ members_page.board_empty: "La liste des membres du bureau sera bientôt disponib
|
||||
members_page.all_title: "Tous les Membres"
|
||||
members_page.all_empty: "Aucun membre n'a été trouvé pour le moment."
|
||||
members_title: 'Membres'
|
||||
# CLÉS DANS LA FICHE DE MEMBRE (Badges et Labels)
|
||||
member_card.role: "Rôle"
|
||||
member_card.cosplay_label: "Cosplayer"
|
||||
member_card.yes: "Oui"
|
||||
@@ -474,22 +442,16 @@ orientation.pansexual: "Pansexuel(le)"
|
||||
orientation.queer: "Queer"
|
||||
orientation.questioning: "En questionnement"
|
||||
orientation.other: "Autre"
|
||||
# --- PAGE D'ACCUEIL (HOMEPAGE.TWIG) ---
|
||||
home_page.title: "Accueil"
|
||||
Boutiques: Boutique
|
||||
# HERO SECTION
|
||||
home_hero.title: "Le Point de Rencontre des Passionnés de Cosplay"
|
||||
home_hero.subtitle: "Rejoignez une communauté inclusive où la créativité, la diversité et l'amitié sont à l'honneur."
|
||||
home_hero.button_members: "Voir nos Membres"
|
||||
home_hero.button_contact: "Nous Contacter"
|
||||
|
||||
# SECTION À PROPOS
|
||||
home_about.pretitle: "Notre Histoire"
|
||||
home_about.title: "Un Espace sûr pour tous les Fandoms"
|
||||
home_about.text_1: "Notre association a été créée pour offrir un environnement bienveillant et structuré à tous les fans d'art vestimentaire, de culture geek et de jeux de rôle."
|
||||
home_about.text_2: "Nous croyons que l'expression personnelle est essentielle. Que vous soyez débutant ou expérimenté, crosscosplayer, transgenre, ou simplement passionné par un univers, vous avez votre place ici."
|
||||
|
||||
# SECTION ACTIVITÉS
|
||||
home_activities.title: "Ce que nous Faisons Ensemble"
|
||||
home_activities.cosplay_title: "Création & Partage de Cosplay"
|
||||
home_activities.cosplay_text: "Des ateliers pour améliorer vos techniques (couture, armure, maquillage) et des séances photo thématiques."
|
||||
@@ -497,16 +459,12 @@ home_activities.community_title: "Événements et Communauté"
|
||||
home_activities.community_text: "Organisation de rencontres régionales, de sorties en convention et de soirées de jeux de société ou de discussions autour d'anime/manga."
|
||||
home_activities.diversity_title: "Diversité et Soutien"
|
||||
home_activities.diversity_text: "Nous sommes un pilier de soutien pour tous, incluant le crossplay et l'accueil bienveillant des membres transgenres et de toutes les orientations."
|
||||
|
||||
# CTA ADHÉSION
|
||||
home_cta.title: "Prêt à Partager votre Passion ?"
|
||||
home_cta.subtitle: "Adhérez aujourd'hui et faites partie de l'aventure."
|
||||
home_cta.button: "Adhérer Maintenant"
|
||||
home_page.description: "Bienvenue dans la communauté e-cosplay ! Votre référence pour les concours, ateliers de craft, et l'entraide. Le cosplay est pour tous, rejoignez notre passion !"
|
||||
members_description: 'Découvrez les membres actifs de notre association de cosplay ! Rencontrez les bénévoles, juges et organisateurs qui donnent vie à nos événements et activités.'
|
||||
contact_page.description: 'Contactez-nous pour toute question sur le cosplay, les événements ou les partenariats ! Formulaire de contact direct et emails des fondatrices disponibles ici.'
|
||||
|
||||
# --- PAGE BOUTIQUE (SHOP.TWIG) ---
|
||||
shop.title: "Boutique | En construction"
|
||||
shop.description: "Découvrez bientôt notre boutique officielle pour les produits dérivés de l'association."
|
||||
breadcrumb.shop: "Boutique"
|
||||
@@ -515,8 +473,6 @@ shop.status_message: "Nous travaillons activement pour préparer notre boutique
|
||||
shop.button_home: "Retour à l'Accueil"
|
||||
shop.button_contact: "Nous Contacter"
|
||||
shop.status_notification: "Suivez nos réseaux sociaux pour être le premier informé de l'ouverture !"
|
||||
|
||||
# --- PAGE ÉVÉNEMENTS (EVENTS.TWIG) ---
|
||||
events.title: "Événements | Bientôt disponible"
|
||||
events.description: "Consultez bientôt le calendrier de nos prochains événements, conventions et rencontres communautaires."
|
||||
breadcrumb.events: "Événements"
|
||||
@@ -526,7 +482,6 @@ events.no_events_message: "Il semble qu'il n'y ait aucun événement de prévu p
|
||||
events.button_contact: "Nous Contacter"
|
||||
login_link: Connexion
|
||||
register_link: Inscription
|
||||
|
||||
breadcrumb.login: Connexion
|
||||
label.email: Adresse e-mail
|
||||
label.password: Mot de passe
|
||||
@@ -535,26 +490,22 @@ button.sign_in: Se connecter
|
||||
link.forgot_password: Mot de passe oublié ?
|
||||
error.login_failed: Échec de la connexion.
|
||||
security.login: Connexion à votre compte
|
||||
|
||||
events.forgot_password: Mot de passe oublié
|
||||
|
||||
# Breadcrumbs (Fil d'Ariane)
|
||||
breadcrumb.forgot_password: Mot de passe oublié
|
||||
|
||||
# Texte descriptif
|
||||
text.enter_email_for_reset: Veuillez entrer votre adresse e-mail pour recevoir un lien de réinitialisation.
|
||||
|
||||
# Bouton
|
||||
button.send_reset_link: Envoyer le lien de réinitialisation
|
||||
|
||||
# Liens
|
||||
link.back_to_login: Retour à la connexion
|
||||
|
||||
|
||||
events.reset_email_sent: E-mail de réinitialisation envoyé
|
||||
|
||||
text.check_inbox_title: Vérifiez votre boîte de réception 📥
|
||||
text.check_inbox_description: Un e-mail a été envoyé avec un lien pour réinitialiser votre mot de passe. Il se peut qu'il arrive dans quelques minutes.
|
||||
text.spam_folder_tip: Si vous ne le voyez pas, vérifiez votre dossier de courriers indésirables (spam).
|
||||
|
||||
# ... (Assurez-vous que 'link.back_to_login' est déjà défini)
|
||||
events.reset_password: Réinitialiser le mot de passe
|
||||
breadcrumb.reset_password: Réinitialisation du mot de passe
|
||||
label.new_password: Nouveau mot de passe
|
||||
label.confirm_password: Confirmer le nouveau mot de passe
|
||||
text.enter_new_password: Veuillez saisir et confirmer votre nouveau mot de passe.
|
||||
button.reset_password: Réinitialiser le mot de passe
|
||||
open_user_menu_sr: Ouvrir le menu utilisateur
|
||||
logged_in_as: Connecté en tant que
|
||||
logout_link: Déconnexion
|
||||
page.login: Connexion
|
||||
|
||||
Reference in New Issue
Block a user