8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-23 11:53:12 +00:00

Improve internationalisation for email templates, scripts, commands and error messages

This commit is contained in:
Laouen Fernet 2019-11-16 14:11:57 +00:00 committed by chirac
parent 7894e3267a
commit e26d21064e
19 changed files with 135 additions and 120 deletions

View file

@ -80,21 +80,21 @@ def hash_password_salt(hashed_password):
try: try:
digest = b64decode(hashed_password[6:]) digest = b64decode(hashed_password[6:])
except TypeError as error: except TypeError as error:
raise ValueError("b64 error for `hashed_password` : %s" % error) raise ValueError("b64 error for `hashed_password`: %s." % error)
if len(digest) < 20: if len(digest) < 20:
raise ValueError("`hashed_password` too short") raise ValueError("`hashed_password` too short.")
return digest[20:] return digest[20:]
elif hashed_password.upper().startswith("{SMD5}"): elif hashed_password.upper().startswith("{SMD5}"):
try: try:
digest = b64decode(hashed_password[7:]) digest = b64decode(hashed_password[7:])
except TypeError as error: except TypeError as error:
raise ValueError("b64 error for `hashed_password` : %s" % error) raise ValueError("b64 error for `hashed_password`: %s." % error)
if len(digest) < 16: if len(digest) < 16:
raise ValueError("`hashed_password` too short") raise ValueError("`hashed_password` too short.")
return digest[16:] return digest[16:]
else: else:
raise ValueError( raise ValueError(
"`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'" "`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'."
) )

View file

@ -64,7 +64,7 @@ class Command(BaseCommand):
for item in os.popen("git shortlog -s -n").read().split("\n") for item in os.popen("git shortlog -s -n").read().split("\n")
if "\t" in item if "\t" in item
] ]
self.stdout.write(self.style.SUCCESS("Exportation Successful")) self.stdout.write(self.style.SUCCESS("Exportation successful!"))
with open("re2o/contributors.py", "w") as contrib_file: with open("re2o/contributors.py", "w") as contrib_file:
content = self._contrib_file_generator(contributors) content = self._contrib_file_generator(contributors)
contrib_file.write(content) contrib_file.write(content)

View file

@ -61,7 +61,7 @@ class FormRevMixin(object):
) )
elif self.changed_data: elif self.changed_data:
reversion.set_comment( reversion.set_comment(
"Field(s) altered : %s" "Field(s) edited: %s"
% ", ".join(field for field in self.changed_data) % ", ".join(field for field in self.changed_data)
) )
return super(FormRevMixin, self).save(*args, **kwargs) return super(FormRevMixin, self).save(*args, **kwargs)

View file

@ -53,7 +53,7 @@ def get_user(pseudo):
raise CommandError("Invalid user.") raise CommandError("Invalid user.")
if len(user) > 1: if len(user) > 1:
raise CommandError( raise CommandError(
"Several users match this username. This SHOULD" " NOT happen." "Several users match this username. This SHOULD NOT happen."
) )
return user[0] return user[0]
@ -95,5 +95,5 @@ def form_cli(Form, user, action, *args, **kwargs):
reversion.set_comment(action) reversion.set_comment(action)
sys.stdout.write( sys.stdout.write(
"%s : done. The edit may take several minutes to" " apply.\n" % action "%s: done. The edit may take several minutes to apply.\n" % action
) )

View file

@ -88,7 +88,7 @@ def get_model(model_name):
app_label, name = splitted app_label, name = splitted
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r is an inconsistent model name" % model_name "%r is an inconsistent model name." % model_name
) )
else: else:
app_label, name = None, splitted[0] app_label, name = None, splitted[0]
@ -101,7 +101,7 @@ def get_model(model_name):
content_type = ContentType.objects.get(model=name.lower()) content_type = ContentType.objects.get(model=name.lower())
except ContentType.DoesNotExist: except ContentType.DoesNotExist:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r is not a valid model for an acl tag" % model_name "%r is not a valid model for an acl tag." % model_name
) )
except ContentType.MultipleObjectsReturned: except ContentType.MultipleObjectsReturned:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
@ -178,7 +178,7 @@ def get_callback(tag_name, obj=None):
True, True,
) )
raise template.TemplateSyntaxError("%r tag is not a valid can_xxx tag" % tag_name) raise template.TemplateSyntaxError("%r tag is not a valid can_xxx tag." % tag_name)
def acl_fct(callback, reverse): def acl_fct(callback, reverse):
@ -264,7 +264,7 @@ def acl_change_filter(parser, token):
args = tag_content[3:] args = tag_content[3:]
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r tag require at least 2 argument: the model and the field" "%r tag require at least 2 argument: the model and the field."
% token.contents.split()[0] % token.contents.split()[0]
) )
@ -306,7 +306,7 @@ def acl_model_filter(parser, token):
args = tag_content[2:] args = tag_content[2:]
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r tag require at least 1 argument: the model" % token.contents.split()[0] "%r tag require at least 1 argument: the model." % token.contents.split()[0]
) )
model = get_model(model_name) model = get_model(model_name)
@ -345,7 +345,7 @@ def acl_instance_filter(parser, token):
args = tag_content[2:] args = tag_content[2:]
except ValueError: except ValueError:
raise template.TemplateSyntaxError( raise template.TemplateSyntaxError(
"%r tag require at least 1 argument: the instance" "%r tag require at least 1 argument: the instance."
% token.contents.split()[0] % token.contents.split()[0]
) )

View file

@ -1,5 +1,5 @@
{% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket. {% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket.
Profil: {{site_url}}{% url 'users:profil' ticket.user.id%} Profile: {{site_url}}{% url 'users:profil' ticket.user.id%}
Answer to the address: {{ticket.user.get_mail}}. Answer to the address: {{ticket.user.get_mail}}.
{% else %} {% else %}

View file

@ -1,9 +1,9 @@
{% if ticket.user %} {{ ticket.user.get_full_name }} à ouvert un ticket. {% if ticket.user %} {{ ticket.user.get_full_name }} a ouvert un ticket.
Profile: {{site_url}}{% url 'users:profil' ticket.user.id%} Profil : {{site_url}}{% url 'users:profil' ticket.user.id%}
Répondre à l'adresse : {{ticket.user.get_mail}}. Répondre à l'adresse : {{ticket.user.get_mail}}.
{% else %} {% else %}
Un utilisateur anonyme (non connecté) à ouvert un ticket. Un utilisateur anonyme (non connecté) a ouvert un ticket.
Répondre à l'adresse : {{ticket.email}}. Répondre à l'adresse : {{ticket.email}}.
{% endif %} {% endif %}

View file

@ -13,7 +13,7 @@ from random import randint
class Command(BaseCommand): class Command(BaseCommand):
help = "Anonymize the data in the database in order to use them on critical servers (dev, personnal...). Every information will be overwritten using non-personnal informations. This script must follow any modification of the database.\nOptionnal argument: {id|id|id|...} to exclude users from anonymisation" help = "Anonymise the data in the database in order to use them on critical servers (dev, personal...). Every information will be overwritten using non-personal information. This script must follow any modification of the database.\nOptional argument: {id|id|id|...} to exclude users from anonymisation."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("user_id", nargs="+", type=int, help="User ID") parser.add_argument("user_id", nargs="+", type=int, help="User ID")
@ -22,7 +22,7 @@ class Command(BaseCommand):
users_ids = kwargs["user_id"] users_ids = kwargs["user_id"]
for user_id in users_ids: for user_id in users_ids:
self.stdout.write( self.stdout.write(
"User: {} will not be anonymised".format( "User: {} will not be anonymised.".format(
User.objects.filter(id=user_id).get().name User.objects.filter(id=user_id).get().name
) )
) )
@ -43,52 +43,52 @@ class Command(BaseCommand):
d = Domain.objects.all() d = Domain.objects.all()
m = Machine.objects.filter(~Q(user_id__in=users_ids)) m = Machine.objects.filter(~Q(user_id__in=users_ids))
self.stdout.write("Supression de l'école...") self.stdout.write("Deletion of the school...")
# Create a fake School to put everyone in it. # Create a fake School to put everyone in it.
ecole = School(name="Ecole des Ninja") ecole = School(name="Ninja School")
ecole.save() ecole.save()
u.update(school=ecole) u.update(school=ecole)
self.stdout.write(self.style.SUCCESS("done ...")) self.stdout.write(self.style.SUCCESS("Done..."))
self.stdout.write("Supression des chambres...") self.stdout.write("Deletion of rooms...")
a.update(room=None) a.update(room=None)
c.update(room=None) c.update(room=None)
self.stdout.write(self.style.SUCCESS("done ...")) self.stdout.write(self.style.SUCCESS("Done..."))
self.stdout.write("Supression des mails...") self.stdout.write("Deletion of email addresses...")
u.update( u.update(
email="example@example.org", email="example@example.org",
local_email_redirect=False, local_email_redirect=False,
local_email_enabled=False, local_email_enabled=False,
) )
self.stdout.write(self.style.SUCCESS("done ...")) self.stdout.write(self.style.SUCCESS("Done..."))
self.stdout.write( self.stdout.write(
"Supression des noms, prenoms, pseudo, telephone, commentaire..." "Deletion of first names, surnames, usernames, telephone numbers, comments..."
) )
a.update(name=Concat(Value("name of "), "id")) a.update(name=Concat(Value("First name of "), "id"))
self.stdout.write(self.style.SUCCESS("done name")) self.stdout.write(self.style.SUCCESS("Done for first names..."))
a.update(surname=Concat(Value("surname of "), "id")) a.update(surname=Concat(Value("Surname of "), "id"))
self.stdout.write(self.style.SUCCESS("done surname")) self.stdout.write(self.style.SUCCESS("Done for surnames..."))
u.update(pseudo=F("id")) u.update(pseudo=F("id"))
self.stdout.write(self.style.SUCCESS("done pseudo")) self.stdout.write(self.style.SUCCESS("Done for usernames..."))
a.update(telephone=Concat(Value("phone of "), "id")) a.update(telephone=Concat(Value("Telephone number of "), "id"))
self.stdout.write(self.style.SUCCESS("done phone")) self.stdout.write(self.style.SUCCESS("Done for telephone numbers..."))
a.update(comment=Concat(Value("commentaire of "), "id")) a.update(comment=Concat(Value("Comment of "), "id"))
self.stdout.write(self.style.SUCCESS("done ...")) self.stdout.write(self.style.SUCCESS("Done for comments..."))
self.stdout.write("Renommage des machines...") self.stdout.write("Renaming of machines...")
m.update( m.update(
name=Concat(Value("Machine "), F("id"), Value(" of "), F("user_id")) name=Concat(Value("Machine "), F("id"), Value(" of "), F("user_id"))
) )
d.update(name=Concat(Value("Domaine id "), F("id"))) d.update(name=Concat(Value("Domain id "), F("id")))
self.stdout.write(self.style.SUCCESS("done ...")) self.stdout.write(self.style.SUCCESS("Done..."))
self.stdout.write("Unification du mot de passe...") self.stdout.write("Unification of the password...")
# Define the password # Define the password
chars = string.ascii_letters + string.digits + "!@#$%^&*()" chars = string.ascii_letters + string.digits + "!@#$%^&*()"
taille = 20 taille = 20
@ -99,19 +99,19 @@ class Command(BaseCommand):
self.stdout.write( self.stdout.write(
self.style.HTTP_NOT_MODIFIED( self.style.HTTP_NOT_MODIFIED(
"The password will be: {}".format(password) "The password will be: {}.".format(password)
) )
) )
u.update(pwd_ntlm=hashNT(password)) u.update(pwd_ntlm=hashNT(password))
u.update(password=makeSecret(password)) u.update(password=makeSecret(password))
self.stdout.write(self.style.SUCCESS("done...")) self.stdout.write(self.style.SUCCESS("Done..."))
self.stdout.write("Suppression de l'historique (This may take some time)") self.stdout.write("Deletion of the history (this may take some time)...")
Revision.objects.all().delete() Revision.objects.all().delete()
self.stdout.write(self.style.SUCCESS("done...")) self.stdout.write(self.style.SUCCESS("Done..."))
self.stdout.write("Data anonymized!") self.stdout.write("Data anonymised!")
else: else:
self.stdout.write("Anonymisation aborted") self.stdout.write("Anonymisation aborted!")

View file

@ -45,14 +45,14 @@ class Command(BaseCommand):
"--full", "--full",
"-f", "-f",
action="store_true", action="store_true",
help="Full archive users, i.e. delete their email address, machines and remove them from the LDAP.", help="Fully archive users, i.e. delete their email address, machines and remove them from the LDAP.",
) )
parser.add_argument( parser.add_argument(
"--date", "--date",
"-d", "-d",
default=datetime.date.today().strftime("%d/%m/%Y"), default=datetime.date.today().strftime("%d/%m/%Y"),
type=valid_date, type=valid_date,
help="Users which membership ends sooner than this date will be archived.", help="Users whose membership ends sooner than this date will be archived.",
) )
parser.add_argument( parser.add_argument(
"--show", "--show",
@ -63,7 +63,7 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"-y", "-y",
action="store_true", action="store_true",
help="Do not ask for confirmation befor full archiving.", help="Do not ask for confirmation before fully archiving.",
) )
def handle(self, *args, **kwargs): def handle(self, *args, **kwargs):
@ -87,7 +87,7 @@ class Command(BaseCommand):
if full_archive and not force: if full_archive and not force:
self.stdout.write( self.stdout.write(
self.style.WARNING( self.style.WARNING(
"Please confirm full archiving (it is a critical operation !) [Y/n]" "Please confirm fully archiving (it is a critical operation!) [Y/n]"
) )
) )
if input() != "Y": if input() != "Y":
@ -95,13 +95,13 @@ class Command(BaseCommand):
return return
if full_archive: if full_archive:
self.stdout.write( self.stdout.write(
"Full archiving users with a membership ending prior to %s" "Fully archiving users with a membership ending prior to %s."
% date.strftime("%d/%m/%Y") % date.strftime("%d/%m/%Y")
) )
User.mass_full_archive(to_archive_list) User.mass_full_archive(to_archive_list)
else: else:
self.stdout.write( self.stdout.write(
"Archiving users with a membership ending prior to %s" "Archiving users with a membership ending prior to %s."
% date.strftime("%d/%m/%Y") % date.strftime("%d/%m/%Y")
) )
to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE) to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE)

View file

@ -28,7 +28,7 @@ from re2o.script_utils import get_user, get_system_user, form_cli
class Command(BaseCommand): class Command(BaseCommand):
help = "Changer le mot de passe d'un utilisateur" help = "Change the password of a user."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("target_username", nargs="?") parser.add_argument("target_username", nargs="?")
@ -44,8 +44,8 @@ class Command(BaseCommand):
if not ok: if not ok:
raise CommandError(msg) raise CommandError(msg)
self.stdout.write("Changement du mot de passe de %s" % target_user.pseudo) self.stdout.write("Password change of %s" % target_user.pseudo)
form_cli( form_cli(
PassForm, current_user, "Changement du mot de passe", instance=target_user PassForm, current_user, "Password change", instance=target_user
) )

View file

@ -32,7 +32,7 @@ from re2o.script_utils import get_user, get_system_user
class Command(BaseCommand): class Command(BaseCommand):
help = "Change the default shell of a user" help = "Change the default shell of a user."
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("target_username", nargs="?") parser.add_argument("target_username", nargs="?")
@ -52,37 +52,36 @@ class Command(BaseCommand):
shells = ListShell.objects.all() shells = ListShell.objects.all()
current_shell = "inconnu" current_shell = "unknown"
if target_user.shell: if target_user.shell:
current_shell = target_user.shell.get_pretty_name() current_shell = target_user.shell.get_pretty_name()
self.stdout.write( self.stdout.write(
"Choisissez un shell pour l'utilisateur %s (le shell actuel est " "Choose a shell for the user %s (the current shell is"
" %s):" % (target_user.pseudo, current_shell) " %s):" % (target_user.pseudo, current_shell)
) )
for shell in shells: for shell in shells:
self.stdout.write( self.stdout.write(
"%d - %s (%s)" % (shell.id, shell.get_pretty_name(), shell.shell) "%d - %s (%s)" % (shell.id, shell.get_pretty_name(), shell.shell)
) )
shell_id = input("Entrez un nombre : ") shell_id = input("Enter a number: ")
try: try:
shell_id = int(shell_id) shell_id = int(shell_id)
except: except:
raise CommandError("Choix invalide") raise CommandError("Invalid choice.")
shell = ListShell.objects.filter(id=shell_id) shell = ListShell.objects.filter(id=shell_id)
if not shell: if not shell:
raise CommandError("Choix invalide") raise CommandError("Invalid choice.")
target_user.shell = shell.first() target_user.shell = shell.first()
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
target_user.save() target_user.save()
reversion.set_user(current_user) reversion.set_user(current_user)
reversion.set_comment("Shell modifié") reversion.set_comment("Shell changed.")
self.stdout.write( self.stdout.write(
self.style.SUCCESS( self.style.SUCCESS(
"Shell modifié. La modification peut prendre quelques minutes " "Shell changed. The change may take a few minutes to apply."
"pour s'appliquer."
) )
) )

View file

@ -27,7 +27,7 @@ from django.utils import timezone
class Command(BaseCommand): class Command(BaseCommand):
help = "Delete non members users (not yet active)" help = "Delete non members users (not yet active)."
def handle(self, *args, **options): def handle(self, *args, **options):
"""First deleting invalid invoices, and then deleting the users""" """First deleting invalid invoices, and then deleting the users"""
@ -38,6 +38,6 @@ class Command(BaseCommand):
.exclude(facture__valid=True) .exclude(facture__valid=True)
.distinct() .distinct()
) )
print("Deleting " + str(users_to_delete.count()) + " users") print("Deleting " + str(users_to_delete.count()) + " users.")
Facture.objects.filter(user__in=users_to_delete).delete() Facture.objects.filter(user__in=users_to_delete).delete()
users_to_delete.delete() users_to_delete.delete()

View file

@ -58,7 +58,7 @@ DATE_FORMATS = [
class Command(BaseCommand): class Command(BaseCommand):
help = ( help = (
"Update the time of the latest connection for users by matching" "Update the time of the latest connection for users by matching"
"stdin against a set of regular expressions" " stdin against a set of regular expressions."
) )
def handle(self, *args, **options): def handle(self, *args, **options):

View file

@ -109,6 +109,6 @@ class Command(BaseCommand):
server = settings.DATABASES["ldap"]["NAME"] server = settings.DATABASES["ldap"]["NAME"]
flush_ldap(binddn, bindpass, server, usersdn, groupsdn) flush_ldap(binddn, bindpass, server, usersdn, groupsdn)
self.stdout.write("LDAP emptied") self.stdout.write("LDAP emptied.")
sync_ldap() sync_ldap()
self.stdout.write("LDAP rebuilt") self.stdout.write("LDAP rebuilt.")

View file

@ -22,7 +22,7 @@ from users.models import User
class Command(BaseCommand): class Command(BaseCommand):
help = "Synchronise le ldap à partir du sql. A utiliser dans un cron" help = "Synchronise the LDAP from SQL. To be used in a cron."
def add_arguments(self, parser): def add_arguments(self, parser):
@ -32,7 +32,7 @@ class Command(BaseCommand):
action="store_true", action="store_true",
dest="full", dest="full",
default=False, default=False,
help="Régénération complète du ldap (y compris des machines)", help="Complete regeneration of the LDAP (including machines).",
) )
def handle(self, *args, **options): def handle(self, *args, **options):

View file

@ -1,27 +1,31 @@
<p>Bonjour {{nom}} </p> <p>Bonjour {{ nom }},</p>
<p>Une nouvelle machine a automatiquement été inscrite sur votre compte.</p> <p>Une nouvelle machine a automatiquement été inscrite sur votre compte.</p>
<p>Si vous êtes à l'origine de la connexion de cet appareil en filaire ou wifi, ne tenez pas compte de cette notification</p> <p>Si vous êtes à l'origine de la connexion de cet appareil en filaire ou Wi-Fi, ne tenez pas compte de ce mail.</p>
<p>La nouvelle machine possède l'adresse mac {{ mac_address }}, et s'est vu assigner le nom suivant : {{ interface_name }}</p> <p>La nouvelle machine possède l'adresse MAC {{ mac_address }}, et s'est vu assigner le nom suivant : {{ interface_name }}.</p>
<p>Vous pouvez à tout moment modifier ces informations sur votre compte en ligne</p> <p>Vous pouvez à tout moment modifier ces informations sur votre compte en ligne.</p>
<p>Si vous n'êtes pas à l'origine de cette connexion, merci de le signaler rapidement à {{asso_email}}</p> <p>Si vous n'êtes pas à l'origine de cette connexion, veuillez le signaler rapidement à {{ asso_email }}.</p>
<p>À bientôt,<br> <p>Respectueusement,<br>
L'équipe de {{ asso_name }}.</p> L'équipe de {{ asso_name }}.</p>
<p>---</p> <p>---</p>
<p>A new device has been automatically added on your account.</p> <p>Hello {{ nom }},</p>
<p>If you connected a new device recently, please don't take this mail into account<p> <p>A new machine has been automatically added on your account.</p>
<p>The new device has this mac address : {{ mac_address }}, and this name : {{ interface_name }}</p> <p>If you are the one who connected this machine with wire of Wi-Fi, don't take this mail into account.<p>
<p>Please contact us if you didn't connect a new device with this mail address {{asso_email}}.</p> <p>The new machine has this MAC address: {{ mac_address }}, and has been assigned this name: {{ interface_name }}</p>
<p>At any time, you can edit this information on your online account.</p>
<p>If you didn't connect this machine, please report it quickly to {{ asso_email }}.</p>
<p>Regards,<br> <p>Regards,<br>
The {{ asso_name }} team.</p> The {{ asso_name }} team.</p>

View file

@ -1,8 +1,19 @@
Bonjour {{name}}, <p>Bonjour {{ name }},</p>
Vous avez été banni par un administrateur de {{ asso_name }} en raison de {{raison}}. Vous n'avez plus accès au réseau jusqu'au {{date_end}}. <p>Vous avez été banni par un administrateur de {{ asso_name }} pour la raison suivante : {{ raison }}. Vous n'avez plus accès au réseau jusqu'au {{ date_end }}.</p>
Pour de plus amples informations, rendez-vous à l'accueil de {{ asso_name }}. <p>Pour de plus amples renseignements, contactez le comité de direction de {{ asso_name }}.</p>
Cordialement, <p>Respectueusement,<br>
L'équipe de {{ asso_name }}. L'équipe de {{ asso_name }}.</p>
<p>---</p>
<p>Hello {{ name }},</p>
<p>You have been banned by a administrator of {{ asso_name }} for the following reason: {{ raison }}. You don't have access to the network anymore until {{ date_end }}.</p>
<p>For more information, contact the steering committee of {{ asso_name }}.</p>
<p>Regards,<br>
The {{ asso_name }} team.</p>

View file

@ -1,33 +1,33 @@
Bonjour {{ name }}, Bonjour {{ name }},
Vous trouverez ci-dessous une url permetant d'initialiser ou de reinitialiser votre Vous trouverez ci-dessous une URL permettant d'initialiser ou de réinitialiser votre
compte {{ site_name }}. Celui-ci vous permet de gérer l'ensemble de vos équipements mot de passe pour votre compte {{ site_name }}. Celui-ci vous permet de gérer l'ensemble
connectés, votre compte, vos factures, et tous les services proposés sur le réseau. de vos équipements, votre compte, vos factures, et tous les services proposés sur le réseau.
{{ url }} {{ url }}
Contactez les administrateurs si vous n'êtes pas à l'origine de cette requête. Contactez les administrateurs si vous n'êtes pas à l'origine de cette requête.
Ce lien expirera dans {{ expire_in }}. Ce lien expirera dans {{ expire_in }} heures.
Cordialement, Respectueusement,
L'équipe de {{ asso }} (contact : {{ asso_mail }}). L'équipe de {{ asso }} (contact : {{ asso_mail }}).
---------------------- ---
Hi {{ name }}, Hello {{ name }},
You will find a link allowing you to change the password of your account on {{ site_name }}. You will find below an URL allowing you to set or reset your the password of your account
On this website you will then be able to manage your devices on the {{ asso }}. on {{ site_name }}. It enables you to manage your devices, your account, your invoices, and all
the services offered on the network.
{{ url }} {{ url }}
This link will expire in {{ expire_in }}. Contact the administrators if you didn't request this.
Send an email at {{ asso_mail }} if you didn't request this or if you have This link will expire in {{ expire_in }} hours.
any other question.
Thanks Regards,
The team of {{ asso }} (contact : {{ asso_mail }}). The {{ asso }} team (contact: {{ asso_mail }}).

View file

@ -2,7 +2,7 @@
<p>Il vous suffit maintenant de payer l'adhésion pour devenir adhérent de {{asso_name}} et bénéficier des services. Pour avoir accès à Internet, il vous faudra payer la connexion.</p> <p>Il vous suffit maintenant de payer l'adhésion pour devenir adhérent de {{asso_name}} et bénéficier des services. Pour avoir accès à Internet, il vous faudra payer la connexion.</p>
<p>Pour ce faire, rien de plus simple. Une fois que vous aurez défini votre mot de passe, il vous suffira d'accéder à votre profil et de cliquer sur 'Payer la connexion'</p> <p>Pour ce faire, rien de plus simple. Une fois que vous aurez défini votre mot de passe, il vous suffira d'accéder à votre profil et de cliquer sur « Payer une connexion »</p>
<p>Votre pseudo est : {{pseudo}}</p> <p>Votre pseudo est : {{pseudo}}</p>
@ -10,21 +10,22 @@
<p>Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}.</p> <p>Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}.</p>
<p>À bientôt,<br> <p>Respectueusement,<br>
L'équipe de {{asso_name}}.</p> L'équipe de {{asso_name}}.</p>
<p>---</p> <p>---</p>
<p>You just need to pay membership to become a full member of {{asso_name}} and benefit from the services. To have Internet access, you will need to pay the connexion. </p> <p>Hello {{nom}}!</p>
<p>Nothing could be simpler. Once your password is defined, you just need to visit your profile and click on 'Pay for a connexion'.</p> <p>You just need to pay the membership fee to become a contributing member of {{asso_name}} and benefit from the services. To get Internet access, you will need to pay the connection.</p>
<p>Nothing could be simpler. Once your password is defined, you just need to access your profile and click on "Pay for a connection".</p>
<p>Your username is: {{pseudo}}<p> <p>Your username is: {{pseudo}}<p>
{{welcome_mail_en|safe}} {{welcome_mail_en|safe}}
<p>For any information, suggestion or problem, you can contact us via email at<br> <p>To express any comment, suggestion or problem, you can send us an email to {{asso_email}}.</p>
{{asso_email}}.</p>
<p>Regards,<br> <p>Regards,<br>
The {{asso_name}} team.</p> The {{asso_name}} team.</p>