Commit e26d2106 authored by Laouen Fernet's avatar Laouen Fernet Committed by chirac

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

parent 7894e326
......@@ -80,21 +80,21 @@ def hash_password_salt(hashed_password):
try:
digest = b64decode(hashed_password[6:])
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:
raise ValueError("`hashed_password` too short")
raise ValueError("`hashed_password` too short.")
return digest[20:]
elif hashed_password.upper().startswith("{SMD5}"):
try:
digest = b64decode(hashed_password[7:])
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:
raise ValueError("`hashed_password` too short")
raise ValueError("`hashed_password` too short.")
return digest[16:]
else:
raise ValueError(
"`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'"
"`hashed_password` should start with '{SSHA}' or '{CRYPT}' or '{SMD5}'."
)
......
......@@ -64,7 +64,7 @@ class Command(BaseCommand):
for item in os.popen("git shortlog -s -n").read().split("\n")
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:
content = self._contrib_file_generator(contributors)
contrib_file.write(content)
......@@ -61,7 +61,7 @@ class FormRevMixin(object):
)
elif self.changed_data:
reversion.set_comment(
"Field(s) altered : %s"
"Field(s) edited: %s"
% ", ".join(field for field in self.changed_data)
)
return super(FormRevMixin, self).save(*args, **kwargs)
......
......@@ -53,7 +53,7 @@ def get_user(pseudo):
raise CommandError("Invalid user.")
if len(user) > 1:
raise CommandError(
"Several users match this username. This SHOULD" " NOT happen."
"Several users match this username. This SHOULD NOT happen."
)
return user[0]
......@@ -95,5 +95,5 @@ def form_cli(Form, user, action, *args, **kwargs):
reversion.set_comment(action)
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
)
......@@ -88,7 +88,7 @@ def get_model(model_name):
app_label, name = splitted
except ValueError:
raise template.TemplateSyntaxError(
"%r is an inconsistent model name" % model_name
"%r is an inconsistent model name." % model_name
)
else:
app_label, name = None, splitted[0]
......@@ -101,7 +101,7 @@ def get_model(model_name):
content_type = ContentType.objects.get(model=name.lower())
except ContentType.DoesNotExist:
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:
raise template.TemplateSyntaxError(
......@@ -178,7 +178,7 @@ def get_callback(tag_name, obj=None):
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):
......@@ -264,7 +264,7 @@ def acl_change_filter(parser, token):
args = tag_content[3:]
except ValueError:
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]
)
......@@ -306,7 +306,7 @@ def acl_model_filter(parser, token):
args = tag_content[2:]
except ValueError:
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)
......@@ -345,7 +345,7 @@ def acl_instance_filter(parser, token):
args = tag_content[2:]
except ValueError:
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]
)
......
{% 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}}.
{% else %}
......
{% if ticket.user %} {{ ticket.user.get_full_name }} à ouvert un ticket.
Profile: {{site_url}}{% url 'users:profil' ticket.user.id%}
Répondre à l'adresse: {{ticket.user.get_mail}}.
{% if ticket.user %} {{ ticket.user.get_full_name }} a ouvert un ticket.
Profil : {{site_url}}{% url 'users:profil' ticket.user.id%}
Répondre à l'adresse : {{ticket.user.get_mail}}.
{% else %}
Un utilisateur anonyme (non connecté) à ouvert un ticket.
Répondre à l'adresse: {{ticket.email}}.
Un utilisateur anonyme (non connecté) a ouvert un ticket.
Répondre à l'adresse : {{ticket.email}}.
{% endif %}
Titre: {{ticket.title}}
Titre : {{ticket.title}}
Description: {{ticket.description}}
Description : {{ticket.description}}
......@@ -13,7 +13,7 @@ from random import randint
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):
parser.add_argument("user_id", nargs="+", type=int, help="User ID")
......@@ -22,14 +22,14 @@ class Command(BaseCommand):
users_ids = kwargs["user_id"]
for user_id in users_ids:
self.stdout.write(
"User: {} will not be anonymised".format(
"User: {} will not be anonymised.".format(
User.objects.filter(id=user_id).get().name
)
)
self.stdout.write(
self.style.WARNING(
"\nDISCLAIMER\nThis function will make your database unusable for production. Are you sure you want to run this ?(doit): "
"\nDISCLAIMER\nThis function will make your database unusable for production. Are you sure you want to run this? (doit): "
)
)
if input() == "doit":
......@@ -43,52 +43,52 @@ class Command(BaseCommand):
d = Domain.objects.all()
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.
ecole = School(name="Ecole des Ninja")
ecole = School(name="Ninja School")
ecole.save()
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)
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(
email="example@example.org",
local_email_redirect=False,
local_email_enabled=False,
)
self.stdout.write(self.style.SUCCESS("done ..."))
self.stdout.write(self.style.SUCCESS("Done..."))
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"))
self.stdout.write(self.style.SUCCESS("done name"))
a.update(name=Concat(Value("First name of "), "id"))
self.stdout.write(self.style.SUCCESS("Done for first names..."))
a.update(surname=Concat(Value("surname of "), "id"))
self.stdout.write(self.style.SUCCESS("done surname"))
a.update(surname=Concat(Value("Surname of "), "id"))
self.stdout.write(self.style.SUCCESS("Done for surnames..."))
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"))
self.stdout.write(self.style.SUCCESS("done phone"))
a.update(telephone=Concat(Value("Telephone number of "), "id"))
self.stdout.write(self.style.SUCCESS("Done for telephone numbers..."))
a.update(comment=Concat(Value("commentaire of "), "id"))
self.stdout.write(self.style.SUCCESS("done ..."))
a.update(comment=Concat(Value("Comment of "), "id"))
self.stdout.write(self.style.SUCCESS("Done for comments..."))
self.stdout.write("Renommage des machines...")
self.stdout.write("Renaming of machines...")
m.update(
name=Concat(Value("Machine "), F("id"), Value(" of "), F("user_id"))
)
d.update(name=Concat(Value("Domaine id "), F("id")))
self.stdout.write(self.style.SUCCESS("done ..."))
d.update(name=Concat(Value("Domain id "), F("id")))
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
chars = string.ascii_letters + string.digits + "!@#$%^&*()"
taille = 20
......@@ -99,19 +99,19 @@ class Command(BaseCommand):
self.stdout.write(
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(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()
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:
self.stdout.write("Anonymisation aborted")
self.stdout.write("Anonymisation aborted!")
......@@ -45,14 +45,14 @@ class Command(BaseCommand):
"--full",
"-f",
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(
"--date",
"-d",
default=datetime.date.today().strftime("%d/%m/%Y"),
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(
"--show",
......@@ -63,7 +63,7 @@ class Command(BaseCommand):
parser.add_argument(
"-y",
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):
......@@ -87,7 +87,7 @@ class Command(BaseCommand):
if full_archive and not force:
self.stdout.write(
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":
......@@ -95,13 +95,13 @@ class Command(BaseCommand):
return
if full_archive:
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")
)
User.mass_full_archive(to_archive_list)
else:
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")
)
to_archive_list = to_archive_list.exclude(state=User.STATE_ARCHIVE)
......
......@@ -28,7 +28,7 @@ from re2o.script_utils import get_user, get_system_user, form_cli
class Command(BaseCommand):
help = "Changer le mot de passe d'un utilisateur"
help = "Change the password of a user."
def add_arguments(self, parser):
parser.add_argument("target_username", nargs="?")
......@@ -44,8 +44,8 @@ class Command(BaseCommand):
if not ok:
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(
PassForm, current_user, "Changement du mot de passe", instance=target_user
PassForm, current_user, "Password change", instance=target_user
)
......@@ -32,7 +32,7 @@ from re2o.script_utils import get_user, get_system_user
class Command(BaseCommand):
help = "Change the default shell of a user"
help = "Change the default shell of a user."
def add_arguments(self, parser):
parser.add_argument("target_username", nargs="?")
......@@ -52,37 +52,36 @@ class Command(BaseCommand):
shells = ListShell.objects.all()
current_shell = "inconnu"
current_shell = "unknown"
if target_user.shell:
current_shell = target_user.shell.get_pretty_name()
self.stdout.write(
"Choisissez un shell pour l'utilisateur %s (le shell actuel est "
"%s) :" % (target_user.pseudo, current_shell)
"Choose a shell for the user %s (the current shell is"
" %s):" % (target_user.pseudo, current_shell)
)
for shell in shells:
self.stdout.write(
"%d - %s (%s)" % (shell.id, shell.get_pretty_name(), shell.shell)
)
shell_id = input("Entrez un nombre : ")
shell_id = input("Enter a number: ")
try:
shell_id = int(shell_id)
except:
raise CommandError("Choix invalide")
raise CommandError("Invalid choice.")
shell = ListShell.objects.filter(id=shell_id)
if not shell:
raise CommandError("Choix invalide")
raise CommandError("Invalid choice.")
target_user.shell = shell.first()
with transaction.atomic(), reversion.create_revision():
target_user.save()
reversion.set_user(current_user)
reversion.set_comment("Shell modifié")
reversion.set_comment("Shell changed.")
self.stdout.write(
self.style.SUCCESS(
"Shell modifié. La modification peut prendre quelques minutes "
"pour s'appliquer."
"Shell changed. The change may take a few minutes to apply."
)
)
......@@ -27,7 +27,7 @@ from django.utils import timezone
class Command(BaseCommand):
help = "Delete non members users (not yet active)"
help = "Delete non members users (not yet active)."
def handle(self, *args, **options):
"""First deleting invalid invoices, and then deleting the users"""
......@@ -38,6 +38,6 @@ class Command(BaseCommand):
.exclude(facture__valid=True)
.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()
users_to_delete.delete()
......@@ -57,8 +57,8 @@ DATE_FORMATS = [
class Command(BaseCommand):
help = (
"Update the time of the latest connection for users by matching "
"stdin against a set of regular expressions"
"Update the time of the latest connection for users by matching"
" stdin against a set of regular expressions."
)
def handle(self, *args, **options):
......
......@@ -96,8 +96,8 @@ def sync_ldap():
class Command(BaseCommand):
help = (
"Destroy the current LDAP data and rebuild it from the DB data. "
"Use with caution."
"Destroy the current LDAP data and rebuild it from the DB data."
" Use with caution."
)
def handle(self, *args, **options):
......@@ -109,6 +109,6 @@ class Command(BaseCommand):
server = settings.DATABASES["ldap"]["NAME"]
flush_ldap(binddn, bindpass, server, usersdn, groupsdn)
self.stdout.write("LDAP emptied")
self.stdout.write("LDAP emptied.")
sync_ldap()
self.stdout.write("LDAP rebuilt")
self.stdout.write("LDAP rebuilt.")
......@@ -22,7 +22,7 @@ from users.models import User
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):
......@@ -32,7 +32,7 @@ class Command(BaseCommand):
action="store_true",
dest="full",
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):
......
<p>Bonjour {{nom}} </p>
<p>Bonjour {{ nom }},</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>
L'équipe de {{asso_name}}.</p>
<p>Respectueusement,<br>
L'équipe de {{ asso_name }}.</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>
The {{asso_name}} team.</p>
The {{ asso_name }} team.</p>
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,
L'équipe de {{ asso_name }}.
<p>Respectueusement,<br>
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>
Bonjour {{ name }},
Vous trouverez ci-dessous une url permetant d'initialiser ou de reinitialiser votre
compte {{ site_name }}. Celui-ci vous permet de gérer l'ensemble de vos équipements
connectés, votre compte, vos factures, et tous les services proposés sur le réseau.
Vous trouverez ci-dessous une URL permettant d'initialiser ou de réinitialiser votre
mot de passe pour votre compte {{ site_name }}. Celui-ci vous permet de gérer l'ensemble
de vos équipements, votre compte, vos factures, et tous les services proposés sur le réseau.
{{ url }}
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 }}).
----------------------
---
Hi {{ name }},
Hello {{ name }},
You will find a link allowing you to change the password of your account on {{ site_name }}.
On this website you will then be able to manage your devices on the {{ asso }}.
You will find below an URL allowing you to set or reset your the password of your account
on {{ site_name }}. It enables you to manage your devices, your account, your invoices, and all
the services offered on the network.
{{ 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
any other question.
This link will expire in {{ expire_in }} hours.
Thanks
Regards,
The team of {{ asso }} (contact : {{ asso_mail }}).
The {{ asso }} team (contact: {{ asso_mail }}).
......@@ -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>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>
......@@ -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>À bientôt,<br>
<p>Respectueusement,<br>
L'équipe de {{asso_name}}.</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>Your username is : {{pseudo}}<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>
{{welcome_mail_en|safe}}
<p>For any information, suggestion or problem, you can contact us via email at<br>
{{asso_email}}.</p>
<p>To express any comment, suggestion or problem, you can send us an email to {{asso_email}}.</p>
<p>Regards,<br>
The {{asso_name}} team.</p>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment