Localization: add python strings

This commit is contained in:
augustin64 2024-01-22 16:06:03 +01:00
parent 2ff7a515d5
commit 210ab6c0d3
13 changed files with 556 additions and 60 deletions

4
.gitignore vendored
View File

@ -1,6 +1,10 @@
# cache # cache
**/__pycache__ **/__pycache__
# translations
**.mo
**.pot
# config # config
.vscode/ .vscode/

View File

@ -27,6 +27,7 @@ git clone https://github.com/partitioncloud/partitioncloud-server.git
cd partitioncloud-server cd partitioncloud-server
# Install dependencies # Install dependencies
pip install -r requirements.txt pip install -r requirements.txt
pybabel compile -d partitioncloud/translations
# Create database and folders # Create database and folders
./make.sh init ./make.sh init
``` ```
@ -66,6 +67,30 @@ Modifier le fichier de configuration créé dans `instance/`
![Recherche](https://github.com/partitioncloud/partitioncloud-server/assets/67148092/745bf3e3-37e9-40cd-80d2-14670bce1a45) ![Recherche](https://github.com/partitioncloud/partitioncloud-server/assets/67148092/745bf3e3-37e9-40cd-80d2-14670bce1a45)
## Translations
### Créer une nouvelle traduction
```bash
# Extraire les données
pybabel extract -F babel.cfg -k _l -o partitioncloud/translations/messages.pot .
# Créer un nouveau fichier
pybabel init -i partitioncloud/translations/messages.pot -d partitioncloud/translations -l $COUNTRY_CODE
# Modifier translations/$COUNTRY_CODE/LC_MESSAGES/messages.po
# Ajouter $COUNTRY_CODE dans default_config.py: LANGUAGES
# Compiler les nouvelles translations avant de démarrer le serveur
pybabel compile -d partitioncloud/translations
```
### Mettre à jour une traduction
```bash
# Récupérer les données les plus récentes
pybabel extract -F babel.cfg -k _l -o partitioncloud/translations/messages.pot .
# Les ajouter aux traductions
pybabel update -i partitioncloud/translations/messages.pot -d partitioncloud/translations
```
## TODO ## TODO
- [ ] Modifier son mot de passe - [ ] Modifier son mot de passe
- [ ] Supprimer un utilisateur - [ ] Supprimer un utilisateur

2
babel.cfg Normal file
View File

@ -0,0 +1,2 @@
[python: partitioncloud/**.py]
[jinja2: partitioncloud/templates/**.html]

View File

@ -26,4 +26,7 @@ MAX_AGE=31
INSTANCE_PATH="instance" INSTANCE_PATH="instance"
# Events to log # Events to log
ENABLED_LOGS=["NEW_GROUPE", "NEW_ALBUM", "NEW_PARTITION", "NEW_USER", "SERVER_RESTART", "FAILED_LOGIN"] ENABLED_LOGS=["NEW_GROUPE", "NEW_ALBUM", "NEW_PARTITION", "NEW_USER", "SERVER_RESTART", "FAILED_LOGIN"]
# Available languages
LANGUAGES=['en', 'fr']

View File

@ -10,6 +10,7 @@ import importlib.util
from flask import Flask, g, redirect, render_template, request, send_file, flash, session, abort from flask import Flask, g, redirect, render_template, request, send_file, flash, session, abort
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
from flask_babel import Babel, _
from .modules.utils import User, Album, get_all_albums from .modules.utils import User, Album, get_all_albums
from .modules import albums, auth, partition, admin, groupe, thumbnails, logging from .modules import albums, auth, partition, admin, groupe, thumbnails, logging
@ -18,6 +19,12 @@ from .modules.db import get_db
app = Flask(__name__) app = Flask(__name__)
def get_locale():
return request.accept_languages.best_match(app.config['LANGUAGES'])
babel = Babel(app, locale_selector=get_locale)
def load_config(): def load_config():
app.config.from_object('default_config') app.config.from_object('default_config')
@ -125,10 +132,10 @@ def add_user():
try: try:
if album_uuid != "": if album_uuid != "":
user.join_album(album_uuid) user.join_album(album_uuid)
flash(f"Utilisateur {username} créé") flash(_("Utilisateur %(username)s créé", username=username))
return redirect("/albums") return redirect("/albums")
except LookupError: except LookupError:
flash(f"Cet album n'existe pas. L'utilisateur {username} a été créé") flash(_("Cet album n'existe pas. L'utilisateur %(username)s a été créé", username=username))
return redirect("/albums") return redirect("/albums")
flash(error) flash(error)

View File

@ -9,6 +9,7 @@ from typing import TypeVar
from flask import (Blueprint, abort, flash, redirect, render_template, from flask import (Blueprint, abort, flash, redirect, render_template,
request, session, current_app) request, session, current_app)
from flask_babel import _
from .auth import login_required from .auth import login_required
from .db import get_db from .db import get_db
@ -37,7 +38,7 @@ def search_page():
Résultats de recherche Résultats de recherche
""" """
if "query" not in request.form or request.form["query"] == "": if "query" not in request.form or request.form["query"] == "":
flash("Aucun terme de recherche spécifié.") flash(_("Aucun terme de recherche spécifié."))
return redirect("/albums") return redirect("/albums")
query = request.form["query"] query = request.form["query"]
@ -119,7 +120,7 @@ def create_album_req():
user = User(user_id=session["user_id"]) user = User(user_id=session["user_id"])
if not name or name.strip() == "": if not name or name.strip() == "":
error = "Un nom est requis. L'album n'a pas été créé" error = _("Un nom est requis. L'album n'a pas été créé")
if error is None: if error is None:
uuid = utils.create_album(name) uuid = utils.create_album(name)
@ -156,10 +157,10 @@ def join_album(uuid):
try: try:
user.join_album(uuid) user.join_album(uuid)
except LookupError: except LookupError:
flash("Cet album n'existe pas.") flash(_("Cet album n'existe pas."))
return redirect(request.referrer) return redirect(request.referrer)
flash("Album ajouté à la collection.") flash(_("Album ajouté à la collection."))
return redirect(request.referrer) return redirect(request.referrer)
@ -173,15 +174,15 @@ def quit_album(uuid):
album = Album(uuid=uuid) album = Album(uuid=uuid)
users = album.get_users() users = album.get_users()
if user.id not in [u["id"] for u in users]: if user.id not in [u["id"] for u in users]:
flash("Vous ne faites pas partie de cet album") flash(_("Vous ne faites pas partie de cet album"))
return redirect(request.referrer) return redirect(request.referrer)
if len(users) == 1: if len(users) == 1:
flash("Vous êtes seul dans cet album, le quitter entraînera sa suppression.") flash(_("Vous êtes seul dans cet album, le quitter entraînera sa suppression."))
return redirect(f"/albums/{uuid}#delete") return redirect(f"/albums/{uuid}#delete")
user.quit_album(uuid) user.quit_album(uuid)
flash("Album quitté.") flash(_("Album quitté."))
return redirect("/albums") return redirect("/albums")
@ -200,9 +201,9 @@ def delete_album(uuid):
error = None error = None
users = album.get_users() users = album.get_users()
if len(users) > 1: if len(users) > 1:
error = "Vous n'êtes pas seul dans cet album." error = _("Vous n'êtes pas seul dans cet album.")
elif len(users) == 1 and users[0]["id"] != user.id: elif len(users) == 1 and users[0]["id"] != user.id:
error = "Vous ne possédez pas cet album." error = _("Vous ne possédez pas cet album.")
if user.access_level == 1: if user.access_level == 1:
error = None error = None
@ -213,7 +214,7 @@ def delete_album(uuid):
album.delete(current_app.instance_path) album.delete(current_app.instance_path)
flash("Album supprimé.") flash(_("Album supprimé."))
return redirect("/albums") return redirect("/albums")
@ -236,15 +237,15 @@ def add_partition(album_uuid):
source = "upload" # source type: upload, unknown or url source = "upload" # source type: upload, unknown or url
if (not user.is_participant(album.uuid)) and (user.access_level != 1): if (not user.is_participant(album.uuid)) and (user.access_level != 1):
flash("Vous ne participez pas à cet album.") flash(_("Vous ne faites pas partie de cet album"))
return redirect(request.referrer) return redirect(request.referrer)
error = None error = None
if "name" not in request.form: if "name" not in request.form:
error = "Un titre est requis." error = _("Un titre est requis.")
elif "file" not in request.files and "partition-uuid" not in request.form: elif "file" not in request.files and "partition-uuid" not in request.form:
error = "Aucun fichier n'a été fourni." error = _("Aucun fichier n'a été fourni.")
elif "file" not in request.files: elif "file" not in request.files:
partition_type = "uuid" partition_type = "uuid"
search_uuid = request.form["partition-uuid"] search_uuid = request.form["partition-uuid"]
@ -256,7 +257,7 @@ def add_partition(album_uuid):
(search_uuid,) (search_uuid,)
).fetchone() ).fetchone()
if data is None: if data is None:
error = "Les résultats de la recherche ont expiré." error = _("Les résultats de la recherche ont expiré.")
else: else:
source = data["url"] source = data["url"]
else: else:
@ -322,7 +323,7 @@ def add_partition(album_uuid):
"status": "ok", "status": "ok",
"uuid": partition_uuid "uuid": partition_uuid
} }
flash(f"Partition {request.form['name']} ajoutée") flash(_("Partition %(partition_name)s ajoutée", partition_name=request.form['name']))
return redirect(f"/albums/{album.uuid}") return redirect(f"/albums/{album.uuid}")
@ -336,13 +337,13 @@ def add_partition_from_search():
error = None error = None
if "album-uuid" not in request.form: if "album-uuid" not in request.form:
error = "Il est nécessaire de sélectionner un album." error = _("Il est nécessaire de sélectionner un album.")
elif "partition-uuid" not in request.form: elif "partition-uuid" not in request.form:
error = "Il est nécessaire de sélectionner une partition." error = _("Il est nécessaire de sélectionner une partition.")
elif "partition-type" not in request.form: elif "partition-type" not in request.form:
error = "Il est nécessaire de spécifier un type de partition." error = _("Il est nécessaire de spécifier un type de partition.")
elif (not user.is_participant(request.form["album-uuid"])) and (user.access_level != 1): elif (not user.is_participant(request.form["album-uuid"])) and (user.access_level != 1):
error = "Vous ne participez pas à cet album." error = _("Vous ne faites pas partie de cet album")
if error is not None: if error is not None:
flash(error) flash(error)
@ -362,9 +363,9 @@ def add_partition_from_search():
if data is None: if data is None:
album.add_partition(request.form["partition-uuid"]) album.add_partition(request.form["partition-uuid"])
flash("Partition ajoutée.") flash(_("Partition ajoutée."))
else: else:
flash("Partition déjà dans l'album.") flash(_("Partition déjà dans l'album."))
return redirect(f"/albums/{album.uuid}") return redirect(f"/albums/{album.uuid}")
@ -376,5 +377,5 @@ def add_partition_from_search():
user=user user=user
) )
flash("Type de partition inconnu.") flash(_("Type de partition inconnu."))
return redirect("/albums") return redirect("/albums")

View File

@ -7,6 +7,7 @@ from typing import Optional
from flask import (Blueprint, flash, g, redirect, render_template, from flask import (Blueprint, flash, g, redirect, render_template,
request, session, url_for, current_app) request, session, url_for, current_app)
from flask_babel import _
from werkzeug.security import check_password_hash, generate_password_hash from werkzeug.security import check_password_hash, generate_password_hash
@ -23,7 +24,7 @@ def login_required(view):
@functools.wraps(view) @functools.wraps(view)
def wrapped_view(**kwargs): def wrapped_view(**kwargs):
if g.user is None: if g.user is None:
flash("Vous devez être connecté pour accéder à cette page.") flash(_("Vous devez être connecté pour accéder à cette page."))
return redirect(url_for("auth.login")) return redirect(url_for("auth.login"))
return view(**kwargs) return view(**kwargs)
@ -50,12 +51,12 @@ def admin_required(view):
@functools.wraps(view) @functools.wraps(view)
def wrapped_view(**kwargs): def wrapped_view(**kwargs):
if g.user is None: if g.user is None:
flash("Vous devez être connecté pour accéder à cette page.") flash(_("Vous devez être connecté pour accéder à cette page."))
return redirect(url_for("auth.login")) return redirect(url_for("auth.login"))
user = User(user_id=session.get("user_id")) user = User(user_id=session.get("user_id"))
if user.access_level != 1: if user.access_level != 1:
flash("Droits insuffisants.") flash(_("Droits insuffisants."))
return redirect("/albums") return redirect("/albums")
return view(**kwargs) return view(**kwargs)
@ -81,9 +82,9 @@ def create_user(username: str, password: str) -> Optional[str]:
"""Adds a new user to the database""" """Adds a new user to the database"""
error = None error = None
if not username: if not username:
error = "Un nom d'utilisateur est requis." error = _("Un nom d'utilisateur est requis.")
elif not password: elif not password:
error = "Un mot de passe est requis." error = _("Un mot de passe est requis.")
try: try:
db = get_db() db = get_db()
@ -96,7 +97,7 @@ def create_user(username: str, password: str) -> Optional[str]:
except db.IntegrityError: except db.IntegrityError:
# The username was already taken, which caused the # The username was already taken, which caused the
# commit to fail. Show a validation error. # commit to fail. Show a validation error.
error = f"Le nom d'utilisateur {username} est déjà pris." error = _("Le nom d'utilisateur %(username)s est déjà pris.", username=username)
return error # may be None return error # may be None
@ -109,7 +110,7 @@ def register():
password for security. password for security.
""" """
if current_app.config["DISABLE_REGISTER"]: if current_app.config["DISABLE_REGISTER"]:
flash("L'enregistrement de nouveaux utilisateurs a été désactivé par l'administrateur.") flash(_("L'enregistrement de nouveaux utilisateurs a été désactivé par l'administrateur."))
return redirect(url_for("auth.login")) return redirect(url_for("auth.login"))
if request.method == "POST": if request.method == "POST":
@ -123,7 +124,7 @@ def register():
else: else:
user = User(name=username) user = User(name=username)
flash("Utilisateur créé avec succès. Vous pouvez vous connecter.") flash(_("Utilisateur créé avec succès. Vous pouvez vous connecter."))
logging.log( logging.log(
[user.username, user.id, False], [user.username, user.id, False],
@ -148,7 +149,7 @@ def login():
if (user is None) or not check_password_hash(user["password"], password): if (user is None) or not check_password_hash(user["password"], password):
logging.log([username], logging.LogEntry.FAILED_LOGIN) logging.log([username], logging.LogEntry.FAILED_LOGIN)
error = "Nom d'utilisateur ou mot de passe incorrect." error = _("Nom d'utilisateur ou mot de passe incorrect.")
if error is None: if error is None:
# store the user id in a new session and return to the index # store the user id in a new session and return to the index

View File

@ -4,6 +4,7 @@ Groupe module
""" """
from flask import (Blueprint, abort, flash, redirect, render_template, from flask import (Blueprint, abort, flash, redirect, render_template,
request, session, current_app) request, session, current_app)
from flask_babel import _
from .auth import login_required from .auth import login_required
from .db import get_db from .db import get_db
@ -67,7 +68,7 @@ def create_groupe():
user = User(user_id=session["user_id"]) user = User(user_id=session["user_id"])
if not name or name.strip() == "": if not name or name.strip() == "":
error = "Un nom est requis. Le groupe n'a pas été créé" error = _("Un nom est requis. Le groupe n'a pas été créé")
if error is None: if error is None:
while True: while True:
@ -116,10 +117,10 @@ def join_groupe(uuid):
try: try:
user.join_groupe(uuid) user.join_groupe(uuid)
except LookupError: except LookupError:
flash("Ce groupe n'existe pas.") flash(_("Ce groupe n'existe pas."))
return redirect(f"/groupe/{uuid}") return redirect(f"/groupe/{uuid}")
flash("Groupe ajouté à la collection.") flash(_("Groupe ajouté à la collection."))
return redirect(f"/groupe/{uuid}") return redirect(f"/groupe/{uuid}")
@ -130,15 +131,15 @@ def quit_groupe(uuid):
groupe = Groupe(uuid=uuid) groupe = Groupe(uuid=uuid)
users = groupe.get_users() users = groupe.get_users()
if user.id not in [u["id"] for u in users]: if user.id not in [u["id"] for u in users]:
flash("Vous ne faites pas partie de ce groupe") flash(_("Vous ne faites pas partie de ce groupe"))
return redirect(f"/groupe/{uuid}") return redirect(f"/groupe/{uuid}")
if len(users) == 1: if len(users) == 1:
flash("Vous êtes seul dans ce groupe, le quitter entraînera sa suppression.") flash(_("Vous êtes seul dans ce groupe, le quitter entraînera sa suppression."))
return redirect(f"/groupe/{uuid}#delete") return redirect(f"/groupe/{uuid}#delete")
user.quit_groupe(groupe.uuid) user.quit_groupe(groupe.uuid)
flash("Groupe quitté.") flash(_("Groupe quitté."))
return redirect("/albums") return redirect("/albums")
@ -151,7 +152,7 @@ def delete_groupe(uuid):
error = None error = None
users = groupe.get_users() users = groupe.get_users()
if len(users) > 1: if len(users) > 1:
error = "Vous n'êtes pas seul dans ce groupe." error = _("Vous n'êtes pas seul dans ce groupe.")
if user.access_level == 1 or user.id not in groupe.get_admins(): if user.access_level == 1 or user.id not in groupe.get_admins():
error = None error = None
@ -162,7 +163,7 @@ def delete_groupe(uuid):
groupe.delete(current_app.instance_path) groupe.delete(current_app.instance_path)
flash("Groupe supprimé.") flash(_("Groupe supprimé."))
return redirect("/albums") return redirect("/albums")
@ -181,10 +182,10 @@ def create_album_req(groupe_uuid):
error = None error = None
if not name or name.strip() == "": if not name or name.strip() == "":
error = "Un nom est requis. L'album n'a pas été créé" error = _("Un nom est requis. L'album n'a pas été créé")
if user.id not in groupe.get_admins(): if user.id not in groupe.get_admins():
error ="Vous n'êtes pas administrateur de ce groupe" error = _("Vous n'êtes pas administrateur de ce groupe")
if error is None: if error is None:
uuid = utils.create_album(name) uuid = utils.create_album(name)

View File

@ -30,7 +30,7 @@ class LogEntry(Enum):
def add_entry(entry: str) -> None: def add_entry(entry: str) -> None:
date = datetime.now().strftime("%y-%b-%Y %H:%M:%S") date = datetime.now().strftime('%y-%b-%Y %H:%M:%S')
with open(log_file, 'a', encoding="utf8") as f: with open(log_file, 'a', encoding="utf8") as f:
f.write(f"[{date}] {entry}\n") f.write(f"[{date}] {entry}\n")

View File

@ -6,6 +6,7 @@ import os
from uuid import uuid4 from uuid import uuid4
from flask import (Blueprint, abort, send_file, render_template, from flask import (Blueprint, abort, send_file, render_template,
request, redirect, flash, session, current_app) request, redirect, flash, session, current_app)
from flask_babel import _
from .db import get_db from .db import get_db
from .auth import login_required, admin_required from .auth import login_required, admin_required
@ -54,12 +55,12 @@ def add_attachment(uuid):
user = User(user_id=session.get("user_id")) user = User(user_id=session.get("user_id"))
if user.id != partition.user_id and user.access_level != 1: if user.id != partition.user_id and user.access_level != 1:
flash("Cette partition ne vous current_appartient pas") flash(_("Cette partition ne vous appartient pas"))
return redirect(request.referrer) return redirect(request.referrer)
error = None # À mettre au propre error = None # À mettre au propre
if "file" not in request.files: if "file" not in request.files:
error = "Aucun fichier n'a été fourni." error = _("Aucun fichier n'a été fourni.")
else: else:
if "name" not in request.form or request.form["name"] == "": if "name" not in request.form or request.form["name"] == "":
name = ".".join(request.files["file"].filename.split(".")[:-1]) name = ".".join(request.files["file"].filename.split(".")[:-1])
@ -67,12 +68,12 @@ def add_attachment(uuid):
name = request.form["name"] name = request.form["name"]
if name == "": if name == "":
error = "Pas de nom de fichier" error = _("Pas de nom de fichier")
else: else:
filename = request.files["file"].filename filename = request.files["file"].filename
ext = filename.split(".")[-1] ext = filename.split(".")[-1]
if ext not in ["mid", "mp3"]: if ext not in ["mid", "mp3"]:
error = "Extension de fichier non supportée" error = _("Extension de fichier non supportée")
if error is not None: if error is not None:
flash(error) flash(error)
@ -140,7 +141,7 @@ def edit(uuid):
user = User(user_id=session.get("user_id")) user = User(user_id=session.get("user_id"))
if user.access_level != 1 and partition.user_id != user.id: if user.access_level != 1 and partition.user_id != user.id:
flash("Vous n'êtes pas autorisé à modifier cette partition.") flash(_("Vous n'êtes pas autorisé à modifier cette partition."))
return redirect("/albums") return redirect("/albums")
if request.method == "GET": if request.method == "GET":
@ -149,11 +150,11 @@ def edit(uuid):
error = None error = None
if "name" not in request.form or request.form["name"].strip() == "": if "name" not in request.form or request.form["name"].strip() == "":
error = "Un titre est requis." error = _("Un titre est requis.")
elif "author" not in request.form: elif "author" not in request.form:
error = "Un nom d'auteur est requis (à minima nul)" error = _("Un nom d'auteur est requis (à minima nul)")
elif "body" not in request.form: elif "body" not in request.form:
error = "Des paroles sont requises (à minima nulles)" error = _("Des paroles sont requises (à minima nulles)")
if error is not None: if error is not None:
flash(error) flash(error)
@ -165,7 +166,7 @@ def edit(uuid):
body=request.form["body"] body=request.form["body"]
) )
flash(f"Partition {request.form['name']} modifiée avec succès.") flash(_("Partition %(name)s modifiée avec succès.", name=request.form['name']))
return redirect("/albums") return redirect("/albums")
@ -195,11 +196,11 @@ def details(uuid):
error = None error = None
if "name" not in request.form or request.form["name"].strip() == "": if "name" not in request.form or request.form["name"].strip() == "":
error = "Un titre est requis." error = _("Un titre est requis.")
elif "author" not in request.form: elif "author" not in request.form:
error = "Un nom d'auteur est requis (à minima nul)" error = _("Un nom d'auteur est requis (à minima nul)")
elif "body" not in request.form: elif "body" not in request.form:
error = "Des paroles sont requises (à minima nulles)" error = _("Des paroles sont requises (à minima nulles)")
if error is not None: if error is not None:
flash(error) flash(error)
@ -211,7 +212,7 @@ def details(uuid):
body=request.form["body"] body=request.form["body"]
) )
flash(f"Partition {request.form['name']} modifiée avec succès.") flash(_("Partition %(name)s modifiée avec succès.", name=request.form['name']))
return redirect("/albums") return redirect("/albums")
@ -226,7 +227,7 @@ def delete(uuid):
user = User(user_id=session.get("user_id")) user = User(user_id=session.get("user_id"))
if user.access_level != 1 and partition.user_id != user.id: if user.access_level != 1 and partition.user_id != user.id:
flash("Vous n'êtes pas autorisé à supprimer cette partition.") flash(_("Vous n'êtes pas autorisé à supprimer cette partition."))
return redirect("/albums") return redirect("/albums")
if request.method == "GET": if request.method == "GET":
@ -234,7 +235,7 @@ def delete(uuid):
partition.delete(current_app.instance_path) partition.delete(current_app.instance_path)
flash("Partition supprimée.") flash(_("Partition supprimée."))
return redirect("/albums") return redirect("/albums")

View File

@ -0,0 +1,224 @@
# English translations for PROJECT.
# Copyright (C) 2024 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-01-22 16:04+0100\n"
"PO-Revision-Date: 2024-01-22 15:38+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n"
"Language-Team: en <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.12.1\n"
#: partitioncloud/__init__.py:136
#, fuzzy, python-format
msgid "Utilisateur %(username)s créé"
msgstr "Created user %(username)s"
#: partitioncloud/__init__.py:139
#, fuzzy, python-format
msgid "Cet album n'existe pas. L'utilisateur %(username)s a été créé"
msgstr "This album does not exists, but user %(username)s has been created"
#: partitioncloud/modules/albums.py:41
msgid "Aucun terme de recherche spécifié."
msgstr "Missing search query"
#: partitioncloud/modules/albums.py:123 partitioncloud/modules/groupe.py:185
msgid "Un nom est requis. L'album n'a pas été créé"
msgstr "Missing name."
#: partitioncloud/modules/albums.py:160
msgid "Cet album n'existe pas."
msgstr "This album does not exist."
#: partitioncloud/modules/albums.py:163
msgid "Album ajouté à la collection."
msgstr "Album added to collection."
#: partitioncloud/modules/albums.py:177 partitioncloud/modules/albums.py:240
#: partitioncloud/modules/albums.py:346
msgid "Vous ne faites pas partie de cet album"
msgstr "You are not a member of this album"
#: partitioncloud/modules/albums.py:181
msgid "Vous êtes seul dans cet album, le quitter entraînera sa suppression."
msgstr "You are alone here, quitting means deleting this album."
#: partitioncloud/modules/albums.py:185
msgid "Album quitté."
msgstr "Album quitted."
#: partitioncloud/modules/albums.py:204
msgid "Vous n'êtes pas seul dans cet album."
msgstr "You are not alone in this album."
#: partitioncloud/modules/albums.py:206
msgid "Vous ne possédez pas cet album."
msgstr "You don't own this album."
#: partitioncloud/modules/albums.py:217
msgid "Album supprimé."
msgstr "Album deleted."
#: partitioncloud/modules/albums.py:246 partitioncloud/modules/partition.py:153
#: partitioncloud/modules/partition.py:199
msgid "Un titre est requis."
msgstr "Missing title"
#: partitioncloud/modules/albums.py:248 partitioncloud/modules/partition.py:63
msgid "Aucun fichier n'a été fourni."
msgstr "Missing file"
#: partitioncloud/modules/albums.py:260
msgid "Les résultats de la recherche ont expiré."
msgstr "Search results expired"
#: partitioncloud/modules/albums.py:326
#, fuzzy, python-format
msgid "Partition %(partition_name)s ajoutée"
msgstr "Score %(partition_name)s added"
#: partitioncloud/modules/albums.py:340
msgid "Il est nécessaire de sélectionner un album."
msgstr "Selecting an album is mandatory."
#: partitioncloud/modules/albums.py:342
msgid "Il est nécessaire de sélectionner une partition."
msgstr "Selecting a score is mandatory."
#: partitioncloud/modules/albums.py:344
msgid "Il est nécessaire de spécifier un type de partition."
msgstr "Please specify a score type."
#: partitioncloud/modules/albums.py:366
msgid "Partition ajoutée."
msgstr "Score added"
#: partitioncloud/modules/albums.py:368
msgid "Partition déjà dans l'album."
msgstr "Score is already in the album."
#: partitioncloud/modules/albums.py:380
msgid "Type de partition inconnu."
msgstr "Unknown score type."
#: partitioncloud/modules/auth.py:27 partitioncloud/modules/auth.py:54
msgid "Vous devez être connecté pour accéder à cette page."
msgstr "You need to login to access this resource."
#: partitioncloud/modules/auth.py:59
msgid "Droits insuffisants."
msgstr "Missing rights."
#: partitioncloud/modules/auth.py:85
msgid "Un nom d'utilisateur est requis."
msgstr "Missing username."
#: partitioncloud/modules/auth.py:87
msgid "Un mot de passe est requis."
msgstr "Missing password."
#: partitioncloud/modules/auth.py:100
#, python-format
msgid "Le nom d'utilisateur %(username)s est déjà pris."
msgstr "Username %(username)s is not available."
#: partitioncloud/modules/auth.py:113
msgid ""
"L'enregistrement de nouveaux utilisateurs a été désactivé par "
"l'administrateur."
msgstr "New users registration is disabled by owner."
#: partitioncloud/modules/auth.py:127
msgid "Utilisateur créé avec succès. Vous pouvez vous connecter."
msgstr "Successfully created new user. You can log in."
#: partitioncloud/modules/auth.py:152
msgid "Nom d'utilisateur ou mot de passe incorrect."
msgstr "Incorrect username or password"
#: partitioncloud/modules/groupe.py:71
msgid "Un nom est requis. Le groupe n'a pas été créé"
msgstr "Missing name."
#: partitioncloud/modules/groupe.py:120
msgid "Ce groupe n'existe pas."
msgstr "Unknown group."
#: partitioncloud/modules/groupe.py:123
msgid "Groupe ajouté à la collection."
msgstr "Group added to collection."
#: partitioncloud/modules/groupe.py:134
msgid "Vous ne faites pas partie de ce groupe"
msgstr "You are not a member of this group."
#: partitioncloud/modules/groupe.py:138
msgid "Vous êtes seul dans ce groupe, le quitter entraînera sa suppression."
msgstr "You are alone here, quitting means deleting this group."
#: partitioncloud/modules/groupe.py:142
msgid "Groupe quitté."
msgstr "Group quitted."
#: partitioncloud/modules/groupe.py:155
msgid "Vous n'êtes pas seul dans ce groupe."
msgstr "You are not alone in this group."
#: partitioncloud/modules/groupe.py:166
msgid "Groupe supprimé."
msgstr "Group deleted."
#: partitioncloud/modules/groupe.py:188
msgid "Vous n'êtes pas administrateur de ce groupe"
msgstr "You are not admin of this group."
#: partitioncloud/modules/partition.py:58
msgid "Cette partition ne vous appartient pas"
msgstr "You don't own this score."
#: partitioncloud/modules/partition.py:71
msgid "Pas de nom de fichier"
msgstr "Missing filename."
#: partitioncloud/modules/partition.py:76
msgid "Extension de fichier non supportée"
msgstr "Unsupported file type."
#: partitioncloud/modules/partition.py:144
msgid "Vous n'êtes pas autorisé à modifier cette partition."
msgstr "You are not allowed to edit this file."
#: partitioncloud/modules/partition.py:155
#: partitioncloud/modules/partition.py:201
msgid "Un nom d'auteur est requis (à minima nul)"
msgstr "Missing author in request body (can be null)."
#: partitioncloud/modules/partition.py:157
#: partitioncloud/modules/partition.py:203
msgid "Des paroles sont requises (à minima nulles)"
msgstr "Missing lyrics (can be null)."
#: partitioncloud/modules/partition.py:169
#: partitioncloud/modules/partition.py:215
#, python-format
msgid "Partition %(name)s modifiée avec succès."
msgstr "Successfully modified %(name)s"
#: partitioncloud/modules/partition.py:230
msgid "Vous n'êtes pas autorisé à supprimer cette partition."
msgstr "You are not allowed to delete this score."
#: partitioncloud/modules/partition.py:238
msgid "Partition supprimée."
msgstr "Score deleted."

View File

@ -0,0 +1,226 @@
# French translations for PROJECT.
# Copyright (C) 2024 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-01-22 16:04+0100\n"
"PO-Revision-Date: 2024-01-22 15:24+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: fr\n"
"Language-Team: fr <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.12.1\n"
#: partitioncloud/__init__.py:136
#, fuzzy, python-format
msgid "Utilisateur %(username)s créé"
msgstr "Utilisateur %(username)s créé"
#: partitioncloud/__init__.py:139
#, fuzzy, python-format
msgid "Cet album n'existe pas. L'utilisateur %(username)s a été créé"
msgstr "Cet album n'existe pas. L'utilisateur %(username)s a été créé"
#: partitioncloud/modules/albums.py:41
msgid "Aucun terme de recherche spécifié."
msgstr "Aucun terme de recherche spécifié."
#: partitioncloud/modules/albums.py:123 partitioncloud/modules/groupe.py:185
msgid "Un nom est requis. L'album n'a pas été créé"
msgstr "Un nom est requis. L'album n'a pas été créé"
#: partitioncloud/modules/albums.py:160
msgid "Cet album n'existe pas."
msgstr "Cet album n'existe pas."
#: partitioncloud/modules/albums.py:163
msgid "Album ajouté à la collection."
msgstr "Album ajouté à la collection."
#: partitioncloud/modules/albums.py:177 partitioncloud/modules/albums.py:240
#: partitioncloud/modules/albums.py:346
msgid "Vous ne faites pas partie de cet album"
msgstr "Vous ne faites pas partie de cet album"
#: partitioncloud/modules/albums.py:181
msgid "Vous êtes seul dans cet album, le quitter entraînera sa suppression."
msgstr "Vous êtes seul dans cet album, le quitter entraînera sa suppression."
#: partitioncloud/modules/albums.py:185
msgid "Album quitté."
msgstr "Album quitté."
#: partitioncloud/modules/albums.py:204
msgid "Vous n'êtes pas seul dans cet album."
msgstr "Vous n'êtes pas seul dans cet album."
#: partitioncloud/modules/albums.py:206
msgid "Vous ne possédez pas cet album."
msgstr "Vous ne possédez pas cet album."
#: partitioncloud/modules/albums.py:217
msgid "Album supprimé."
msgstr "Album supprimé."
#: partitioncloud/modules/albums.py:246 partitioncloud/modules/partition.py:153
#: partitioncloud/modules/partition.py:199
msgid "Un titre est requis."
msgstr "Un titre est requis."
#: partitioncloud/modules/albums.py:248 partitioncloud/modules/partition.py:63
msgid "Aucun fichier n'a été fourni."
msgstr "Aucun fichier n'a été fourni."
#: partitioncloud/modules/albums.py:260
msgid "Les résultats de la recherche ont expiré."
msgstr "Les résultats de la recherche ont expiré."
#: partitioncloud/modules/albums.py:326
#, fuzzy, python-format
msgid "Partition %(partition_name)s ajoutée"
msgstr "Partition %(partition_name)s ajoutée"
#: partitioncloud/modules/albums.py:340
msgid "Il est nécessaire de sélectionner un album."
msgstr "Il est nécessaire de sélectionner un album."
#: partitioncloud/modules/albums.py:342
msgid "Il est nécessaire de sélectionner une partition."
msgstr "Il est nécessaire de sélectionner une partition."
#: partitioncloud/modules/albums.py:344
msgid "Il est nécessaire de spécifier un type de partition."
msgstr "Il est nécessaire de spécifier un type de partition."
#: partitioncloud/modules/albums.py:366
msgid "Partition ajoutée."
msgstr "Partition ajoutée."
#: partitioncloud/modules/albums.py:368
msgid "Partition déjà dans l'album."
msgstr "Partition déjà dans l'album."
#: partitioncloud/modules/albums.py:380
msgid "Type de partition inconnu."
msgstr "Type de partition inconnu."
#: partitioncloud/modules/auth.py:27 partitioncloud/modules/auth.py:54
msgid "Vous devez être connecté pour accéder à cette page."
msgstr "Vous devez être connecté pour accéder à cette page."
#: partitioncloud/modules/auth.py:59
msgid "Droits insuffisants."
msgstr "Droits insuffisants."
#: partitioncloud/modules/auth.py:85
msgid "Un nom d'utilisateur est requis."
msgstr "Un nom d'utilisateur est requis."
#: partitioncloud/modules/auth.py:87
msgid "Un mot de passe est requis."
msgstr "Un mot de passe est requis."
#: partitioncloud/modules/auth.py:100
#, fuzzy, python-format
msgid "Le nom d'utilisateur %(username)s est déjà pris."
msgstr "Le nom d'utilisateur %(username)s est déjà pris."
#: partitioncloud/modules/auth.py:113
msgid ""
"L'enregistrement de nouveaux utilisateurs a été désactivé par "
"l'administrateur."
msgstr ""
"L'enregistrement de nouveaux utilisateurs a été désactivé par "
"l'administrateur."
#: partitioncloud/modules/auth.py:127
msgid "Utilisateur créé avec succès. Vous pouvez vous connecter."
msgstr "Utilisateur créé avec succès. Vous pouvez vous connecter."
#: partitioncloud/modules/auth.py:152
msgid "Nom d'utilisateur ou mot de passe incorrect."
msgstr "Nom d'utilisateur ou mot de passe incorrect."
#: partitioncloud/modules/groupe.py:71
msgid "Un nom est requis. Le groupe n'a pas été créé"
msgstr "Un nom est requis. Le groupe n'a pas été créé"
#: partitioncloud/modules/groupe.py:120
msgid "Ce groupe n'existe pas."
msgstr "Ce groupe n'existe pas."
#: partitioncloud/modules/groupe.py:123
msgid "Groupe ajouté à la collection."
msgstr "Groupe ajouté à la collection."
#: partitioncloud/modules/groupe.py:134
msgid "Vous ne faites pas partie de ce groupe"
msgstr "Vous ne faites pas partie de ce groupe"
#: partitioncloud/modules/groupe.py:138
msgid "Vous êtes seul dans ce groupe, le quitter entraînera sa suppression."
msgstr "Vous êtes seul dans ce groupe, le quitter entraînera sa suppression."
#: partitioncloud/modules/groupe.py:142
msgid "Groupe quitté."
msgstr "Groupe quitté."
#: partitioncloud/modules/groupe.py:155
msgid "Vous n'êtes pas seul dans ce groupe."
msgstr "Vous n'êtes pas seul dans ce groupe."
#: partitioncloud/modules/groupe.py:166
msgid "Groupe supprimé."
msgstr "Groupe supprimé."
#: partitioncloud/modules/groupe.py:188
msgid "Vous n'êtes pas administrateur de ce groupe"
msgstr "Vous n'êtes pas administrateur de ce groupe"
#: partitioncloud/modules/partition.py:58
msgid "Cette partition ne vous appartient pas"
msgstr "Cette partition ne vous appartient pas"
#: partitioncloud/modules/partition.py:71
msgid "Pas de nom de fichier"
msgstr "Pas de nom de fichier"
#: partitioncloud/modules/partition.py:76
msgid "Extension de fichier non supportée"
msgstr "Extension de fichier non supportée"
#: partitioncloud/modules/partition.py:144
msgid "Vous n'êtes pas autorisé à modifier cette partition."
msgstr "Vous n'êtes pas autorisé à modifier cette partition."
#: partitioncloud/modules/partition.py:155
#: partitioncloud/modules/partition.py:201
msgid "Un nom d'auteur est requis (à minima nul)"
msgstr "Un nom d'auteur est requis (à minima nul)"
#: partitioncloud/modules/partition.py:157
#: partitioncloud/modules/partition.py:203
msgid "Des paroles sont requises (à minima nulles)"
msgstr "Des paroles sont requises (à minima nulles)"
#: partitioncloud/modules/partition.py:169
#: partitioncloud/modules/partition.py:215
#, fuzzy, python-format
msgid "Partition %(name)s modifiée avec succès."
msgstr "Partition %(name)s modifiée avec succès."
#: partitioncloud/modules/partition.py:230
msgid "Vous n'êtes pas autorisé à supprimer cette partition."
msgstr "Vous n'êtes pas autorisé à supprimer cette partition."
#: partitioncloud/modules/partition.py:238
msgid "Partition supprimée."
msgstr "Partition supprimée."

View File

@ -1,4 +1,5 @@
flask flask
flask-babel
google google
colorama colorama
qrcode qrcode