mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-28 12:30:00 +00:00
Merge branch 'master' into Develop
# Conflicts: # cps/admin.py # cps/config_sql.py # cps/templates/config_edit.html # cps/web.py
This commit is contained in:
commit
7aabfc573b
22
cps/admin.py
22
cps/admin.py
@ -164,7 +164,6 @@ def view_configuration():
|
|||||||
@login_required
|
@login_required
|
||||||
@admin_required
|
@admin_required
|
||||||
def update_view_configuration():
|
def update_view_configuration():
|
||||||
reboot_required = False
|
|
||||||
to_save = request.form.to_dict()
|
to_save = request.form.to_dict()
|
||||||
|
|
||||||
_config_string = lambda x: config.set_from_dictionary(to_save, x, lambda y: y.strip() if y else y)
|
_config_string = lambda x: config.set_from_dictionary(to_save, x, lambda y: y.strip() if y else y)
|
||||||
@ -172,7 +171,8 @@ def update_view_configuration():
|
|||||||
|
|
||||||
_config_string("config_calibre_web_title")
|
_config_string("config_calibre_web_title")
|
||||||
_config_string("config_columns_to_ignore")
|
_config_string("config_columns_to_ignore")
|
||||||
reboot_required |= _config_string("config_title_regex")
|
if _config_string("config_title_regex"):
|
||||||
|
calibre_db.update_title_sort(config)
|
||||||
|
|
||||||
_config_int("config_read_column")
|
_config_int("config_read_column")
|
||||||
_config_int("config_theme")
|
_config_int("config_theme")
|
||||||
@ -191,10 +191,6 @@ def update_view_configuration():
|
|||||||
config.save()
|
config.save()
|
||||||
flash(_(u"Calibre-Web configuration updated"), category="success")
|
flash(_(u"Calibre-Web configuration updated"), category="success")
|
||||||
before_request()
|
before_request()
|
||||||
if reboot_required:
|
|
||||||
db.dispose()
|
|
||||||
ub.dispose()
|
|
||||||
web_server.stop(True)
|
|
||||||
|
|
||||||
return view_configuration()
|
return view_configuration()
|
||||||
|
|
||||||
@ -614,12 +610,24 @@ def _configuration_ldap_helper(to_save, gdriveError):
|
|||||||
return reboot_required, _configuration_result(_('LDAP User Object Filter Has Unmatched Parenthesis'),
|
return reboot_required, _configuration_result(_('LDAP User Object Filter Has Unmatched Parenthesis'),
|
||||||
gdriveError)
|
gdriveError)
|
||||||
|
|
||||||
|
if to_save["ldap_import_user_filter"] == '0':
|
||||||
|
config.config_ldap_member_user_object = ""
|
||||||
|
else:
|
||||||
|
if config.config_ldap_member_user_object.count("%s") != 1:
|
||||||
|
return reboot_required, \
|
||||||
|
_configuration_result(_('LDAP Member User Filter needs to Have One "%s" Format Identifier'),
|
||||||
|
gdriveError)
|
||||||
|
if config.config_ldap_member_user_object.count("(") != config.config_ldap_member_user_object.count(")"):
|
||||||
|
return reboot_required, _configuration_result(_('LDAP Member User Filter Has Unmatched Parenthesis'),
|
||||||
|
gdriveError)
|
||||||
|
|
||||||
if config.config_ldap_cacert_path or config.config_ldap_cert_path or config.config_ldap_key_path:
|
if config.config_ldap_cacert_path or config.config_ldap_cert_path or config.config_ldap_key_path:
|
||||||
if not (os.path.isfile(config.config_ldap_cacert_path) and
|
if not (os.path.isfile(config.config_ldap_cacert_path) and
|
||||||
os.path.isfile(config.config_ldap_cert_path) and
|
os.path.isfile(config.config_ldap_cert_path) and
|
||||||
os.path.isfile(config.config_ldap_key_path)):
|
os.path.isfile(config.config_ldap_key_path)):
|
||||||
return reboot_required, \
|
return reboot_required, \
|
||||||
_configuration_result(_('LDAP CACertificate, Certificate or Key Location is not Valid, Please Enter Correct Path'),
|
_configuration_result(_('LDAP CACertificate, Certificate or Key Location is not Valid, '
|
||||||
|
'Please Enter Correct Path'),
|
||||||
gdriveError)
|
gdriveError)
|
||||||
return reboot_required, None
|
return reboot_required, None
|
||||||
|
|
||||||
|
@ -113,6 +113,7 @@ class _Settings(_Base):
|
|||||||
config_ldap_key_path = Column(String, default="")
|
config_ldap_key_path = Column(String, default="")
|
||||||
config_ldap_dn = Column(String, default='dc=example,dc=org')
|
config_ldap_dn = Column(String, default='dc=example,dc=org')
|
||||||
config_ldap_user_object = Column(String, default='uid=%s')
|
config_ldap_user_object = Column(String, default='uid=%s')
|
||||||
|
config_ldap_member_user_object = Column(String, default='') #
|
||||||
config_ldap_openldap = Column(Boolean, default=True)
|
config_ldap_openldap = Column(Boolean, default=True)
|
||||||
config_ldap_group_object_filter = Column(String, default='(&(objectclass=posixGroup)(cn=%s))')
|
config_ldap_group_object_filter = Column(String, default='(&(objectclass=posixGroup)(cn=%s))')
|
||||||
config_ldap_group_members_field = Column(String, default='memberUid')
|
config_ldap_group_members_field = Column(String, default='memberUid')
|
||||||
|
@ -935,8 +935,6 @@ def convert_bookformat(book_id):
|
|||||||
@edit_required
|
@edit_required
|
||||||
def edit_list_book(param):
|
def edit_list_book(param):
|
||||||
vals = request.form.to_dict()
|
vals = request.form.to_dict()
|
||||||
# calibre_db.update_title_sort(config)
|
|
||||||
#calibre_db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4()))
|
|
||||||
book = calibre_db.get_book(vals['pk'])
|
book = calibre_db.get_book(vals['pk'])
|
||||||
if param =='series_index':
|
if param =='series_index':
|
||||||
edit_book_series_index(vals['value'], book)
|
edit_book_series_index(vals['value'], book)
|
||||||
|
@ -862,6 +862,7 @@ def HandleUserRequest(dummy=None):
|
|||||||
@kobo.route("/v1/products/<dummy>/recommendations", methods=["GET", "POST"])
|
@kobo.route("/v1/products/<dummy>/recommendations", methods=["GET", "POST"])
|
||||||
@kobo.route("/v1/products/<dummy>/nextread", methods=["GET", "POST"])
|
@kobo.route("/v1/products/<dummy>/nextread", methods=["GET", "POST"])
|
||||||
@kobo.route("/v1/products/<dummy>/reviews", methods=["GET", "POST"])
|
@kobo.route("/v1/products/<dummy>/reviews", methods=["GET", "POST"])
|
||||||
|
@kobo.route("/v1/products/books/external/<dummy>", methods=["GET", "POST"])
|
||||||
@kobo.route("/v1/products/books/series/<dummy>", methods=["GET", "POST"])
|
@kobo.route("/v1/products/books/series/<dummy>", methods=["GET", "POST"])
|
||||||
@kobo.route("/v1/products/books/<dummy>", methods=["GET", "POST"])
|
@kobo.route("/v1/products/books/<dummy>", methods=["GET", "POST"])
|
||||||
@kobo.route("/v1/products/dailydeal", methods=["GET", "POST"])
|
@kobo.route("/v1/products/dailydeal", methods=["GET", "POST"])
|
||||||
|
14
cps/opds.py
14
cps/opds.py
@ -25,7 +25,7 @@ import sys
|
|||||||
import datetime
|
import datetime
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from flask import Blueprint, request, render_template, Response, g, make_response
|
from flask import Blueprint, request, render_template, Response, g, make_response, abort
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from sqlalchemy.sql.expression import func, text, or_, and_
|
from sqlalchemy.sql.expression import func, text, or_, and_
|
||||||
from werkzeug.security import check_password_hash
|
from werkzeug.security import check_password_hash
|
||||||
@ -33,7 +33,7 @@ from werkzeug.security import check_password_hash
|
|||||||
from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages
|
from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages
|
||||||
from .helper import get_download_link, get_book_cover
|
from .helper import get_download_link, get_book_cover
|
||||||
from .pagination import Pagination
|
from .pagination import Pagination
|
||||||
from .web import render_read_books, download_required
|
from .web import render_read_books, download_required, load_user_from_request
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from babel import Locale as LC
|
from babel import Locale as LC
|
||||||
from babel.core import UnknownLocaleError
|
from babel.core import UnknownLocaleError
|
||||||
@ -383,8 +383,13 @@ def feed_shelf(book_id):
|
|||||||
|
|
||||||
@opds.route("/opds/download/<book_id>/<book_format>/")
|
@opds.route("/opds/download/<book_id>/<book_format>/")
|
||||||
@requires_basic_auth_if_no_ano
|
@requires_basic_auth_if_no_ano
|
||||||
@download_required
|
|
||||||
def opds_download_link(book_id, book_format):
|
def opds_download_link(book_id, book_format):
|
||||||
|
# I gave up with this: With enabled ldap login, the user doesn't get logged in, therefore it's always guest
|
||||||
|
# workaround, loading the user from the request and checking it's download rights here
|
||||||
|
# in case of anonymous browsing user is None
|
||||||
|
user = load_user_from_request(request) or current_user
|
||||||
|
if not user.role_download():
|
||||||
|
return abort(403)
|
||||||
if "Kobo" in request.headers.get('User-Agent'):
|
if "Kobo" in request.headers.get('User-Agent'):
|
||||||
client = "kobo"
|
client = "kobo"
|
||||||
else:
|
else:
|
||||||
@ -418,7 +423,10 @@ def feed_search(term):
|
|||||||
|
|
||||||
def check_auth(username, password):
|
def check_auth(username, password):
|
||||||
if sys.version_info.major == 3:
|
if sys.version_info.major == 3:
|
||||||
|
try:
|
||||||
username = username.encode('windows-1252')
|
username = username.encode('windows-1252')
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
username = username.encode('utf-8')
|
||||||
user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) ==
|
user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) ==
|
||||||
username.decode('utf-8').lower()).first()
|
username.decode('utf-8').lower()).first()
|
||||||
return bool(user and check_password_hash(str(user.password), password))
|
return bool(user and check_password_hash(str(user.password), password))
|
||||||
|
@ -117,7 +117,7 @@ def bind_user(username, password):
|
|||||||
return None, error
|
return None, error
|
||||||
except LDAPException as ex:
|
except LDAPException as ex:
|
||||||
if ex.message == 'Invalid credentials':
|
if ex.message == 'Invalid credentials':
|
||||||
error = ("LDAP admin login failed")
|
error = "LDAP admin login failed"
|
||||||
return None, error
|
return None, error
|
||||||
if ex.message == "Can't contact LDAP server":
|
if ex.message == "Can't contact LDAP server":
|
||||||
# log.warning('LDAP Server down: %s', ex)
|
# log.warning('LDAP Server down: %s', ex)
|
||||||
|
@ -23,16 +23,12 @@
|
|||||||
<h3>{{_("In Library")}}</h3>
|
<h3>{{_("In Library")}}</h3>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="filterheader hidden-xs hidden-sm">
|
<div class="filterheader hidden-xs hidden-sm">
|
||||||
<a id="new" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a id="new" data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
<a id="old" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a id="old" data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
<a id="asc" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
<a id="asc" data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||||
<a id="desc" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
<a id="desc" data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||||
<a id="pub_new" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a id="pub_new" data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
<a id="pub_old" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a id="pub_old" data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
<!--div class="btn-group character" role="group">
|
|
||||||
<a id="no_shelf" class="btn btn-primary" href="{{url_for('web.books_list', data='author', book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-list"></span><b>?</b></a>
|
|
||||||
<div id="all" class="btn btn-primary">{{_('All')}}</div>
|
|
||||||
</div-->
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row display-flex">
|
<div class="row display-flex">
|
||||||
{% if entries[0] %}
|
{% if entries[0] %}
|
||||||
|
@ -60,10 +60,10 @@
|
|||||||
<label for="config_google_drive_watch_changes_response">{{_('Metadata Watch Channel ID')}}</label>
|
<label for="config_google_drive_watch_changes_response">{{_('Metadata Watch Channel ID')}}</label>
|
||||||
<div class="form-group input-group required">
|
<div class="form-group input-group required">
|
||||||
<input type="text" class="form-control" name="config_google_drive_watch_changes_response" id="config_google_drive_watch_changes_response" value="{{ config.config_google_drive_watch_changes_response['id'] }} expires on {{ config.config_google_drive_watch_changes_response['expiration'] | strftime }}" autocomplete="off" disabled="">
|
<input type="text" class="form-control" name="config_google_drive_watch_changes_response" id="config_google_drive_watch_changes_response" value="{{ config.config_google_drive_watch_changes_response['id'] }} expires on {{ config.config_google_drive_watch_changes_response['expiration'] | strftime }}" autocomplete="off" disabled="">
|
||||||
<span class="input-group-btn"><a href="{{ url_for('gdrive.revoke_watch_gdrive') }}" class="btn btn-primary">{{_('Revoke')}}</a></span>
|
<span class="input-group-btn"><a href="{{ url_for('gdrive.revoke_watch_gdrive') }}" id="watch_revoke" class="btn btn-primary">{{_('Revoke')}}</a></span>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('gdrive.watch_gdrive') }}" class="btn btn-primary">Enable watch of metadata.db</a>
|
<a href="{{ url_for('gdrive.watch_gdrive') }}" id="enable_gdrive_watch" class="btn btn-primary">Enable watch of metadata.db</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -331,6 +331,20 @@
|
|||||||
<label for="config_ldap_group_members_field">{{_('LDAP Group Members Field')}}</label>
|
<label for="config_ldap_group_members_field">{{_('LDAP Group Members Field')}}</label>
|
||||||
<input type="text" class="form-control" id="config_ldap_group_members_field" name="config_ldap_group_members_field" value="{% if config.config_ldap_group_members_field != None %}{{ config.config_ldap_group_members_field }}{% endif %}" autocomplete="off">
|
<input type="text" class="form-control" id="config_ldap_group_members_field" name="config_ldap_group_members_field" value="{% if config.config_ldap_group_members_field != None %}{{ config.config_ldap_group_members_field }}{% endif %}" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ldap_import_user_filter">{{_('LDAP Authentication')}}</label>
|
||||||
|
<select name="ldap_import_user_filter" id="ldap_import_user_filter" class="form-control" data-control="ldap_member_user_object">
|
||||||
|
<option value="0" {% if config.config_ldap_member_user_object == "" %}selected{% endif %}>{{ _('Autodetect') }}</option>
|
||||||
|
<option value="1" {% if config.config_ldap_member_user_object %}selected{% endif %}>{{ _('Custom Filter') }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div data-related="ldap_member_user_object-1">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="config_ldap_member_user_object">{{_('LDAP Member User Filter')}}</label>
|
||||||
|
<input type="text" class="form-control" id="config_ldap_member_user_object" name="config_ldap_member_user_object" value="{% if config.config_ldap_member_user_object != None %}{{ config.config_ldap_member_user_object }}{% endif %}" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if feature_support['oauth'] %}
|
{% if feature_support['oauth'] %}
|
||||||
|
@ -62,15 +62,18 @@
|
|||||||
<div class="discover load-more">
|
<div class="discover load-more">
|
||||||
<h2 class="{{title}}">{{_(title)}}</h2>
|
<h2 class="{{title}}">{{_(title)}}</h2>
|
||||||
<div class="filterheader hidden-xs hidden-sm">
|
<div class="filterheader hidden-xs hidden-sm">
|
||||||
<a data-toggle="tooltip" id="new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" id="new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
<a id="old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" id="old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
<a id="asc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" id="asc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='abc')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||||
<a id="desc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" id="desc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='zyx')}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||||
<a id="pub_new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort authors in alphabetical order')}}" id="auth_az" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='authaz')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||||
<a id="pub_old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" id="auth_za" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='authza')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||||
<!--div class="btn-group character">
|
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" id="pub_new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
<a id="no_shelf" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-list"></span> <b>{{_('Group by series')}}</b></a>
|
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" id="pub_old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
</div-->
|
{% if page == 'series' %}
|
||||||
|
<a data-toggle="tooltip" title="{{_('Sort ascending according to series index')}}" id="series_asc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='seriesasc')}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
|
<a data-toggle="tooltip" title="{{_('Sort descending according to series index')}}" id="series_desc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, book_id=id, sort_param='seriesdesc')}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row display-flex">
|
<div class="row display-flex">
|
||||||
|
@ -26,12 +26,14 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="filterheader hidden-xs hidden-sm"><!-- ToDo: Implement filter for search results -->
|
<div class="filterheader hidden-xs hidden-sm"><!-- ToDo: Implement filter for search results -->
|
||||||
<a id="new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='new', query=query)}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a id="new" data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='new', query=query)}}"><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
<a id="old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='old', query=query)}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a id="old" data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='old', query=query)}}"><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
<a id="asc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='abc', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
<a id="asc" data-toggle="tooltip" title="{{_('Sort title in alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='abc', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||||
<a id="desc" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='zyx', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
<a id="desc" data-toggle="tooltip" title="{{_('Sort title in reverse alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='zyx', query=query)}}"><span class="glyphicon glyphicon-font"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||||
<a id="pub_new" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='pubnew', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a id="auth_az" data-toggle="tooltip" title="{{_('Sort authors in alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='authaz', query=query)}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet"></span></a>
|
||||||
<a id="pub_old" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='pubold', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a id="auth_za" data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='authza', query=query)}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||||
|
<a id="pub_new" data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='pubnew', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
|
<a id="pub_old" data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" class="btn btn-primary" href="{{url_for('web.books_list', data=page, sort_param='pubold', query=query)}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Calibre-Web\n"
|
"Project-Id-Version: Calibre-Web\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2020-11-14 13:15+0100\n"
|
"POT-Creation-Date: 2020-12-01 14:10+0100\n"
|
||||||
"PO-Revision-Date: 2020-06-07 06:47+0200\n"
|
"PO-Revision-Date: 2020-06-07 06:47+0200\n"
|
||||||
"Last-Translator: Dekani <dekani1500@gmail.com>\n"
|
"Last-Translator: Dekani <dekani1500@gmail.com>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
@ -40,268 +40,268 @@ msgstr "installé"
|
|||||||
msgid "not installed"
|
msgid "not installed"
|
||||||
msgstr "non installé"
|
msgstr "non installé"
|
||||||
|
|
||||||
#: cps/about.py:96
|
#: cps/about.py:99
|
||||||
msgid "Statistics"
|
msgid "Statistics"
|
||||||
msgstr "Statistiques"
|
msgstr "Statistiques"
|
||||||
|
|
||||||
#: cps/admin.py:93
|
#: cps/admin.py:94
|
||||||
msgid "Server restarted, please reload page"
|
msgid "Server restarted, please reload page"
|
||||||
msgstr "Serveur redémarré, merci de rafraîchir la page"
|
msgstr "Serveur redémarré, merci de rafraîchir la page"
|
||||||
|
|
||||||
#: cps/admin.py:95
|
#: cps/admin.py:96
|
||||||
msgid "Performing shutdown of server, please close window"
|
msgid "Performing shutdown of server, please close window"
|
||||||
msgstr "Arrêt du serveur en cours, merci de fermer la fenêtre"
|
msgstr "Arrêt du serveur en cours, merci de fermer la fenêtre"
|
||||||
|
|
||||||
#: cps/admin.py:103
|
#: cps/admin.py:104
|
||||||
msgid "Reconnect successful"
|
msgid "Reconnect successful"
|
||||||
msgstr "Reconnecté avec succès"
|
msgstr "Reconnecté avec succès"
|
||||||
|
|
||||||
#: cps/admin.py:106
|
#: cps/admin.py:107
|
||||||
msgid "Unknown command"
|
msgid "Unknown command"
|
||||||
msgstr "Commande inconnue"
|
msgstr "Commande inconnue"
|
||||||
|
|
||||||
#: cps/admin.py:116 cps/editbooks.py:611 cps/editbooks.py:623
|
#: cps/admin.py:117 cps/editbooks.py:611 cps/editbooks.py:623
|
||||||
#: cps/editbooks.py:723 cps/editbooks.py:725 cps/editbooks.py:786
|
#: cps/editbooks.py:726 cps/editbooks.py:728 cps/editbooks.py:789
|
||||||
#: cps/editbooks.py:802 cps/updater.py:510 cps/uploader.py:98
|
#: cps/editbooks.py:805 cps/updater.py:510 cps/uploader.py:98
|
||||||
#: cps/uploader.py:108
|
#: cps/uploader.py:108
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr "Inconnu"
|
msgstr "Inconnu"
|
||||||
|
|
||||||
#: cps/admin.py:137
|
#: cps/admin.py:138
|
||||||
msgid "Admin page"
|
msgid "Admin page"
|
||||||
msgstr "Page admin"
|
msgstr "Page admin"
|
||||||
|
|
||||||
#: cps/admin.py:159
|
#: cps/admin.py:160
|
||||||
msgid "UI Configuration"
|
msgid "UI Configuration"
|
||||||
msgstr "Configuration de l’interface utilisateur"
|
msgstr "Configuration de l’interface utilisateur"
|
||||||
|
|
||||||
#: cps/admin.py:191 cps/admin.py:718
|
#: cps/admin.py:192 cps/admin.py:729
|
||||||
msgid "Calibre-Web configuration updated"
|
msgid "Calibre-Web configuration updated"
|
||||||
msgstr "Configuration de Calibre-Web mise à jour"
|
msgstr "Configuration de Calibre-Web mise à jour"
|
||||||
|
|
||||||
#: cps/admin.py:436 cps/admin.py:442 cps/admin.py:453 cps/admin.py:464
|
#: cps/admin.py:438 cps/admin.py:444 cps/admin.py:455 cps/admin.py:466
|
||||||
#: cps/templates/modal_dialogs.html:29
|
#: cps/templates/modal_dialogs.html:29
|
||||||
msgid "Deny"
|
msgid "Deny"
|
||||||
msgstr "Refuser"
|
msgstr "Refuser"
|
||||||
|
|
||||||
#: cps/admin.py:438 cps/admin.py:444 cps/admin.py:455 cps/admin.py:466
|
#: cps/admin.py:440 cps/admin.py:446 cps/admin.py:457 cps/admin.py:468
|
||||||
#: cps/templates/modal_dialogs.html:28
|
#: cps/templates/modal_dialogs.html:28
|
||||||
msgid "Allow"
|
msgid "Allow"
|
||||||
msgstr "Autoriser"
|
msgstr "Autoriser"
|
||||||
|
|
||||||
#: cps/admin.py:512
|
#: cps/admin.py:514
|
||||||
msgid "client_secrets.json Is Not Configured For Web Application"
|
msgid "client_secrets.json Is Not Configured For Web Application"
|
||||||
msgstr "client_secrets.json n'est pas configuré pour l'application Web"
|
msgstr "client_secrets.json n'est pas configuré pour l'application Web"
|
||||||
|
|
||||||
#: cps/admin.py:551
|
#: cps/admin.py:554
|
||||||
msgid "Logfile Location is not Valid, Please Enter Correct Path"
|
msgid "Logfile Location is not Valid, Please Enter Correct Path"
|
||||||
msgstr "L'emplacement du fichier logfile est incorrect, veuillez saisir un chemin valide"
|
msgstr "L'emplacement du fichier logfile est incorrect, veuillez saisir un chemin valide"
|
||||||
|
|
||||||
#: cps/admin.py:556
|
#: cps/admin.py:560
|
||||||
msgid "Access Logfile Location is not Valid, Please Enter Correct Path"
|
msgid "Access Logfile Location is not Valid, Please Enter Correct Path"
|
||||||
msgstr "L'emplacement du fichier Access Logfile est incorrect, veuillez saisir un chemin valide"
|
msgstr "L'emplacement du fichier Access Logfile est incorrect, veuillez saisir un chemin valide"
|
||||||
|
|
||||||
#: cps/admin.py:582
|
#: cps/admin.py:586
|
||||||
msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier"
|
msgid "Please Enter a LDAP Provider, Port, DN and User Object Identifier"
|
||||||
msgstr "Veuillez saisir un fournisseur LDAP, Port, DN et l'identifiant objet de l'utilisateur"
|
msgstr "Veuillez saisir un fournisseur LDAP, Port, DN et l'identifiant objet de l'utilisateur"
|
||||||
|
|
||||||
#: cps/admin.py:595
|
#: cps/admin.py:601
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier"
|
msgid "LDAP Group Object Filter Needs to Have One \"%s\" Format Identifier"
|
||||||
msgstr "Le filtre objet du groupe LDAP a besoin d'un identifiant de format \"%s\""
|
msgstr "Le filtre objet du groupe LDAP a besoin d'un identifiant de format \"%s\""
|
||||||
|
|
||||||
#: cps/admin.py:598
|
#: cps/admin.py:604
|
||||||
msgid "LDAP Group Object Filter Has Unmatched Parenthesis"
|
msgid "LDAP Group Object Filter Has Unmatched Parenthesis"
|
||||||
msgstr "Le filtre objet du groupe LDAP a une parenthèse non gérée"
|
msgstr "Le filtre objet du groupe LDAP a une parenthèse non gérée"
|
||||||
|
|
||||||
#: cps/admin.py:602
|
#: cps/admin.py:609
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier"
|
msgid "LDAP User Object Filter needs to Have One \"%s\" Format Identifier"
|
||||||
msgstr "Le filtre objet de l'utilisateur LDAP a besoin d'un identifiant de format \"%s\""
|
msgstr "Le filtre objet de l'utilisateur LDAP a besoin d'un identifiant de format \"%s\""
|
||||||
|
|
||||||
#: cps/admin.py:605
|
#: cps/admin.py:612
|
||||||
msgid "LDAP User Object Filter Has Unmatched Parenthesis"
|
msgid "LDAP User Object Filter Has Unmatched Parenthesis"
|
||||||
msgstr "Le filtre objet de l'utilisateur LDAP a une parenthèse non gérée"
|
msgstr "Le filtre objet de l'utilisateur LDAP a une parenthèse non gérée"
|
||||||
|
|
||||||
#: cps/admin.py:609
|
#: cps/admin.py:617
|
||||||
msgid "LDAP Certificate Location is not Valid, Please Enter Correct Path"
|
msgid "LDAP Certificate Location is not Valid, Please Enter Correct Path"
|
||||||
msgstr "L'emplacement du certificat LDAP est incorrect, veuillez saisir un chemin valide"
|
msgstr "L'emplacement du certificat LDAP est incorrect, veuillez saisir un chemin valide"
|
||||||
|
|
||||||
#: cps/admin.py:631
|
#: cps/admin.py:642
|
||||||
msgid "Keyfile Location is not Valid, Please Enter Correct Path"
|
msgid "Keyfile Location is not Valid, Please Enter Correct Path"
|
||||||
msgstr "L'emplacement du fichier Keyfile est incorrect, veuillez saisir un chemin valide"
|
msgstr "L'emplacement du fichier Keyfile est incorrect, veuillez saisir un chemin valide"
|
||||||
|
|
||||||
#: cps/admin.py:635
|
#: cps/admin.py:646
|
||||||
msgid "Certfile Location is not Valid, Please Enter Correct Path"
|
msgid "Certfile Location is not Valid, Please Enter Correct Path"
|
||||||
msgstr "L'emplacement du fichier Certfile est incorrect, veuillez saisir un chemin valide"
|
msgstr "L'emplacement du fichier Certfile est incorrect, veuillez saisir un chemin valide"
|
||||||
|
|
||||||
#: cps/admin.py:701 cps/admin.py:800 cps/admin.py:890 cps/admin.py:939
|
#: cps/admin.py:712 cps/admin.py:811 cps/admin.py:901 cps/admin.py:950
|
||||||
#: cps/shelf.py:100 cps/shelf.py:161 cps/shelf.py:202 cps/shelf.py:260
|
#: cps/shelf.py:100 cps/shelf.py:161 cps/shelf.py:202 cps/shelf.py:260
|
||||||
#: cps/shelf.py:309 cps/shelf.py:338 cps/shelf.py:368 cps/shelf.py:392
|
#: cps/shelf.py:309 cps/shelf.py:338 cps/shelf.py:368 cps/shelf.py:392
|
||||||
msgid "Settings DB is not Writeable"
|
msgid "Settings DB is not Writeable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cps/admin.py:713
|
#: cps/admin.py:724
|
||||||
msgid "DB Location is not Valid, Please Enter Correct Path"
|
msgid "DB Location is not Valid, Please Enter Correct Path"
|
||||||
msgstr "L'emplacement DB est incorrect, veuillez saisir un chemin valide"
|
msgstr "L'emplacement DB est incorrect, veuillez saisir un chemin valide"
|
||||||
|
|
||||||
#: cps/admin.py:715
|
#: cps/admin.py:726
|
||||||
msgid "DB is not Writeable"
|
msgid "DB is not Writeable"
|
||||||
msgstr "La DB n'est pas accessible en écriture"
|
msgstr "La DB n'est pas accessible en écriture"
|
||||||
|
|
||||||
#: cps/admin.py:748
|
#: cps/admin.py:759
|
||||||
msgid "Basic Configuration"
|
msgid "Basic Configuration"
|
||||||
msgstr "Configuration principale"
|
msgstr "Configuration principale"
|
||||||
|
|
||||||
#: cps/admin.py:763 cps/web.py:1508
|
#: cps/admin.py:774 cps/web.py:1508
|
||||||
msgid "Please fill out all fields!"
|
msgid "Please fill out all fields!"
|
||||||
msgstr "Veuillez compléter tous les champs !"
|
msgstr "Veuillez compléter tous les champs !"
|
||||||
|
|
||||||
#: cps/admin.py:766 cps/admin.py:778 cps/admin.py:784 cps/admin.py:908
|
#: cps/admin.py:777 cps/admin.py:789 cps/admin.py:795 cps/admin.py:919
|
||||||
msgid "Add new user"
|
msgid "Add new user"
|
||||||
msgstr "Ajouter un nouvel utilisateur"
|
msgstr "Ajouter un nouvel utilisateur"
|
||||||
|
|
||||||
#: cps/admin.py:775 cps/web.py:1754
|
#: cps/admin.py:786 cps/web.py:1754
|
||||||
msgid "E-mail is not from valid domain"
|
msgid "E-mail is not from valid domain"
|
||||||
msgstr "Cette adresse de courriel n’appartient pas à un domaine valide"
|
msgstr "Cette adresse de courriel n’appartient pas à un domaine valide"
|
||||||
|
|
||||||
#: cps/admin.py:782 cps/admin.py:797
|
#: cps/admin.py:793 cps/admin.py:808
|
||||||
msgid "Found an existing account for this e-mail address or nickname."
|
msgid "Found an existing account for this e-mail address or nickname."
|
||||||
msgstr "Un compte existant a été trouvé pour cette adresse de courriel ou pour ce surnom."
|
msgstr "Un compte existant a été trouvé pour cette adresse de courriel ou pour ce surnom."
|
||||||
|
|
||||||
#: cps/admin.py:793
|
#: cps/admin.py:804
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User '%(user)s' created"
|
msgid "User '%(user)s' created"
|
||||||
msgstr "Utilisateur '%(user)s' créé"
|
msgstr "Utilisateur '%(user)s' créé"
|
||||||
|
|
||||||
#: cps/admin.py:809
|
#: cps/admin.py:820
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User '%(nick)s' deleted"
|
msgid "User '%(nick)s' deleted"
|
||||||
msgstr "Utilisateur '%(nick)s' supprimé"
|
msgstr "Utilisateur '%(nick)s' supprimé"
|
||||||
|
|
||||||
#: cps/admin.py:812
|
#: cps/admin.py:823
|
||||||
msgid "No admin user remaining, can't delete user"
|
msgid "No admin user remaining, can't delete user"
|
||||||
msgstr "Aucun utilisateur admin restant, impossible de supprimer l’utilisateur"
|
msgstr "Aucun utilisateur admin restant, impossible de supprimer l’utilisateur"
|
||||||
|
|
||||||
#: cps/admin.py:818
|
#: cps/admin.py:829
|
||||||
msgid "No admin user remaining, can't remove admin role"
|
msgid "No admin user remaining, can't remove admin role"
|
||||||
msgstr "Aucun utilisateur admin restant, impossible de supprimer le rôle admin"
|
msgstr "Aucun utilisateur admin restant, impossible de supprimer le rôle admin"
|
||||||
|
|
||||||
#: cps/admin.py:854 cps/web.py:1796
|
#: cps/admin.py:865 cps/web.py:1796
|
||||||
msgid "Found an existing account for this e-mail address."
|
msgid "Found an existing account for this e-mail address."
|
||||||
msgstr "Un compte existant a été trouvé pour cette adresse de courriel."
|
msgstr "Un compte existant a été trouvé pour cette adresse de courriel."
|
||||||
|
|
||||||
#: cps/admin.py:863 cps/admin.py:877 cps/admin.py:980 cps/web.py:1772
|
#: cps/admin.py:874 cps/admin.py:888 cps/admin.py:991 cps/web.py:1772
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Edit User %(nick)s"
|
msgid "Edit User %(nick)s"
|
||||||
msgstr "Éditer l'utilisateur %(nick)s"
|
msgstr "Éditer l'utilisateur %(nick)s"
|
||||||
|
|
||||||
#: cps/admin.py:869 cps/web.py:1765
|
#: cps/admin.py:880 cps/web.py:1765
|
||||||
msgid "This username is already taken"
|
msgid "This username is already taken"
|
||||||
msgstr "Cet utilisateur est déjà pris"
|
msgstr "Cet utilisateur est déjà pris"
|
||||||
|
|
||||||
#: cps/admin.py:884
|
#: cps/admin.py:895
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User '%(nick)s' updated"
|
msgid "User '%(nick)s' updated"
|
||||||
msgstr "Utilisateur '%(nick)s' mis à jour"
|
msgstr "Utilisateur '%(nick)s' mis à jour"
|
||||||
|
|
||||||
#: cps/admin.py:887
|
#: cps/admin.py:898
|
||||||
msgid "An unknown error occured."
|
msgid "An unknown error occured."
|
||||||
msgstr "Oups ! Une erreur inconnue a eu lieu."
|
msgstr "Oups ! Une erreur inconnue a eu lieu."
|
||||||
|
|
||||||
#: cps/admin.py:917 cps/templates/admin.html:71
|
#: cps/admin.py:928 cps/templates/admin.html:71
|
||||||
msgid "Edit E-mail Server Settings"
|
msgid "Edit E-mail Server Settings"
|
||||||
msgstr "Modifier les paramètres du serveur de courriels"
|
msgstr "Modifier les paramètres du serveur de courriels"
|
||||||
|
|
||||||
#: cps/admin.py:946
|
#: cps/admin.py:957
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Test e-mail successfully send to %(kindlemail)s"
|
msgid "Test e-mail successfully send to %(kindlemail)s"
|
||||||
msgstr "Courriel de test envoyé avec succès sur %(kindlemail)s"
|
msgstr "Courriel de test envoyé avec succès sur %(kindlemail)s"
|
||||||
|
|
||||||
#: cps/admin.py:949
|
#: cps/admin.py:960
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "There was an error sending the Test e-mail: %(res)s"
|
msgid "There was an error sending the Test e-mail: %(res)s"
|
||||||
msgstr "Il y a eu une erreur pendant l’envoi du courriel de test : %(res)s"
|
msgstr "Il y a eu une erreur pendant l’envoi du courriel de test : %(res)s"
|
||||||
|
|
||||||
#: cps/admin.py:951
|
#: cps/admin.py:962
|
||||||
msgid "Please configure your e-mail address first..."
|
msgid "Please configure your e-mail address first..."
|
||||||
msgstr "Veuillez d'abord configurer votre adresse de courriel..."
|
msgstr "Veuillez d'abord configurer votre adresse de courriel..."
|
||||||
|
|
||||||
#: cps/admin.py:953
|
#: cps/admin.py:964
|
||||||
msgid "E-mail server settings updated"
|
msgid "E-mail server settings updated"
|
||||||
msgstr "Les paramètres du serveur de courriels ont été mis à jour"
|
msgstr "Les paramètres du serveur de courriels ont été mis à jour"
|
||||||
|
|
||||||
#: cps/admin.py:964
|
#: cps/admin.py:975
|
||||||
msgid "User not found"
|
msgid "User not found"
|
||||||
msgstr "L'utilisateur n'a pas été trouvé"
|
msgstr "L'utilisateur n'a pas été trouvé"
|
||||||
|
|
||||||
#: cps/admin.py:991
|
#: cps/admin.py:1002
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Password for user %(user)s reset"
|
msgid "Password for user %(user)s reset"
|
||||||
msgstr "Le mot de passe de l’utilisateur %(user)s a été réinitialisé"
|
msgstr "Le mot de passe de l’utilisateur %(user)s a été réinitialisé"
|
||||||
|
|
||||||
#: cps/admin.py:994 cps/web.py:1532 cps/web.py:1596
|
#: cps/admin.py:1005 cps/web.py:1532 cps/web.py:1596
|
||||||
msgid "An unknown error occurred. Please try again later."
|
msgid "An unknown error occurred. Please try again later."
|
||||||
msgstr "Une erreur inconnue est survenue. Veuillez réessayer plus tard."
|
msgstr "Une erreur inconnue est survenue. Veuillez réessayer plus tard."
|
||||||
|
|
||||||
#: cps/admin.py:997 cps/web.py:1470
|
#: cps/admin.py:1008 cps/web.py:1470
|
||||||
msgid "Please configure the SMTP mail settings first..."
|
msgid "Please configure the SMTP mail settings first..."
|
||||||
msgstr "Veuillez configurer les paramètres SMTP au préalable..."
|
msgstr "Veuillez configurer les paramètres SMTP au préalable..."
|
||||||
|
|
||||||
#: cps/admin.py:1009
|
#: cps/admin.py:1020
|
||||||
msgid "Logfile viewer"
|
msgid "Logfile viewer"
|
||||||
msgstr "Visualiseur de fichier journal"
|
msgstr "Visualiseur de fichier journal"
|
||||||
|
|
||||||
#: cps/admin.py:1049
|
#: cps/admin.py:1081
|
||||||
msgid "Requesting update package"
|
msgid "Requesting update package"
|
||||||
msgstr "Demande de mise à jour"
|
msgstr "Demande de mise à jour"
|
||||||
|
|
||||||
#: cps/admin.py:1050
|
#: cps/admin.py:1082
|
||||||
msgid "Downloading update package"
|
msgid "Downloading update package"
|
||||||
msgstr "Téléchargement de la mise à jour"
|
msgstr "Téléchargement de la mise à jour"
|
||||||
|
|
||||||
#: cps/admin.py:1051
|
#: cps/admin.py:1083
|
||||||
msgid "Unzipping update package"
|
msgid "Unzipping update package"
|
||||||
msgstr "Décompression de la mise à jour"
|
msgstr "Décompression de la mise à jour"
|
||||||
|
|
||||||
#: cps/admin.py:1052
|
#: cps/admin.py:1084
|
||||||
msgid "Replacing files"
|
msgid "Replacing files"
|
||||||
msgstr "Remplacement des fichiers"
|
msgstr "Remplacement des fichiers"
|
||||||
|
|
||||||
#: cps/admin.py:1053
|
#: cps/admin.py:1085
|
||||||
msgid "Database connections are closed"
|
msgid "Database connections are closed"
|
||||||
msgstr "Les connexions à la base de données ont été fermées"
|
msgstr "Les connexions à la base de données ont été fermées"
|
||||||
|
|
||||||
#: cps/admin.py:1054
|
#: cps/admin.py:1086
|
||||||
msgid "Stopping server"
|
msgid "Stopping server"
|
||||||
msgstr "Arrêt du serveur"
|
msgstr "Arrêt du serveur"
|
||||||
|
|
||||||
#: cps/admin.py:1055
|
#: cps/admin.py:1087
|
||||||
msgid "Update finished, please press okay and reload page"
|
msgid "Update finished, please press okay and reload page"
|
||||||
msgstr "Mise à jour terminée, merci d’appuyer sur okay et de rafraîchir la page"
|
msgstr "Mise à jour terminée, merci d’appuyer sur okay et de rafraîchir la page"
|
||||||
|
|
||||||
#: cps/admin.py:1056 cps/admin.py:1057 cps/admin.py:1058 cps/admin.py:1059
|
#: cps/admin.py:1088 cps/admin.py:1089 cps/admin.py:1090 cps/admin.py:1091
|
||||||
#: cps/admin.py:1060
|
#: cps/admin.py:1092
|
||||||
msgid "Update failed:"
|
msgid "Update failed:"
|
||||||
msgstr "La mise à jour a échoué :"
|
msgstr "La mise à jour a échoué :"
|
||||||
|
|
||||||
#: cps/admin.py:1056 cps/updater.py:320 cps/updater.py:521 cps/updater.py:523
|
#: cps/admin.py:1088 cps/updater.py:320 cps/updater.py:521 cps/updater.py:523
|
||||||
msgid "HTTP Error"
|
msgid "HTTP Error"
|
||||||
msgstr "Erreur HTTP"
|
msgstr "Erreur HTTP"
|
||||||
|
|
||||||
#: cps/admin.py:1057 cps/updater.py:322 cps/updater.py:525
|
#: cps/admin.py:1089 cps/updater.py:322 cps/updater.py:525
|
||||||
msgid "Connection error"
|
msgid "Connection error"
|
||||||
msgstr "Erreur de connexion"
|
msgstr "Erreur de connexion"
|
||||||
|
|
||||||
#: cps/admin.py:1058 cps/updater.py:324 cps/updater.py:527
|
#: cps/admin.py:1090 cps/updater.py:324 cps/updater.py:527
|
||||||
msgid "Timeout while establishing connection"
|
msgid "Timeout while establishing connection"
|
||||||
msgstr "Délai d'attente dépassé lors de l'établissement de connexion"
|
msgstr "Délai d'attente dépassé lors de l'établissement de connexion"
|
||||||
|
|
||||||
#: cps/admin.py:1059 cps/updater.py:326 cps/updater.py:529
|
#: cps/admin.py:1091 cps/updater.py:326 cps/updater.py:529
|
||||||
msgid "General error"
|
msgid "General error"
|
||||||
msgstr "Erreur générale"
|
msgstr "Erreur générale"
|
||||||
|
|
||||||
#: cps/admin.py:1060
|
#: cps/admin.py:1092
|
||||||
msgid "Update File Could Not be Saved in Temp Dir"
|
msgid "Update File Could Not be Saved in Temp Dir"
|
||||||
msgstr "Le fichier de mise à jour ne peut pas être sauvegardé dans le répertoire temporaire"
|
msgstr "Le fichier de mise à jour ne peut pas être sauvegardé dans le répertoire temporaire"
|
||||||
|
|
||||||
@ -335,12 +335,12 @@ msgstr "modifier les métadonnées"
|
|||||||
msgid "%(langname)s is not a valid language"
|
msgid "%(langname)s is not a valid language"
|
||||||
msgstr "%(langname)s n'est pas une langue valide"
|
msgstr "%(langname)s n'est pas une langue valide"
|
||||||
|
|
||||||
#: cps/editbooks.py:512 cps/editbooks.py:768
|
#: cps/editbooks.py:512 cps/editbooks.py:771
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File extension '%(ext)s' is not allowed to be uploaded to this server"
|
msgid "File extension '%(ext)s' is not allowed to be uploaded to this server"
|
||||||
msgstr "L’extension de fichier '%(ext)s' n’est pas autorisée pour être déposée sur ce serveur"
|
msgstr "L’extension de fichier '%(ext)s' n’est pas autorisée pour être déposée sur ce serveur"
|
||||||
|
|
||||||
#: cps/editbooks.py:516 cps/editbooks.py:772
|
#: cps/editbooks.py:516 cps/editbooks.py:775
|
||||||
msgid "File to be uploaded must have an extension"
|
msgid "File to be uploaded must have an extension"
|
||||||
msgstr "Pour être déposé le fichier doit avoir une extension"
|
msgstr "Pour être déposé le fichier doit avoir une extension"
|
||||||
|
|
||||||
@ -354,7 +354,7 @@ msgstr "Impossible de créer le chemin %(path)s (Permission refusée)."
|
|||||||
msgid "Failed to store file %(file)s."
|
msgid "Failed to store file %(file)s."
|
||||||
msgstr "Échec de la sauvegarde du fichier %(file)s."
|
msgstr "Échec de la sauvegarde du fichier %(file)s."
|
||||||
|
|
||||||
#: cps/editbooks.py:551 cps/editbooks.py:903
|
#: cps/editbooks.py:551 cps/editbooks.py:906
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Database error: %(error)s."
|
msgid "Database error: %(error)s."
|
||||||
msgstr "Erreur de la base de données: %(error)s."
|
msgstr "Erreur de la base de données: %(error)s."
|
||||||
@ -364,47 +364,47 @@ msgstr "Erreur de la base de données: %(error)s."
|
|||||||
msgid "File format %(ext)s added to %(book)s"
|
msgid "File format %(ext)s added to %(book)s"
|
||||||
msgstr "Le format de fichier %(ext)s a été ajouté à %(book)s"
|
msgstr "Le format de fichier %(ext)s a été ajouté à %(book)s"
|
||||||
|
|
||||||
#: cps/editbooks.py:672
|
#: cps/editbooks.py:675
|
||||||
msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier"
|
msgid "Identifiers are not Case Sensitive, Overwriting Old Identifier"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cps/editbooks.py:709
|
#: cps/editbooks.py:712
|
||||||
msgid "Metadata successfully updated"
|
msgid "Metadata successfully updated"
|
||||||
msgstr "Les métadonnées ont bien été mises à jour"
|
msgstr "Les métadonnées ont bien été mises à jour"
|
||||||
|
|
||||||
#: cps/editbooks.py:718
|
#: cps/editbooks.py:721
|
||||||
msgid "Error editing book, please check logfile for details"
|
msgid "Error editing book, please check logfile for details"
|
||||||
msgstr "Erreur d’édition du livre, veuillez consulter le journal (log) pour plus de détails"
|
msgstr "Erreur d’édition du livre, veuillez consulter le journal (log) pour plus de détails"
|
||||||
|
|
||||||
#: cps/editbooks.py:780
|
#: cps/editbooks.py:783
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File %(filename)s could not saved to temp dir"
|
msgid "File %(filename)s could not saved to temp dir"
|
||||||
msgstr "Le fichier %(filename)s ne peut pas être sauvegardé dans le répertoire temporaire"
|
msgstr "Le fichier %(filename)s ne peut pas être sauvegardé dans le répertoire temporaire"
|
||||||
|
|
||||||
#: cps/editbooks.py:790
|
#: cps/editbooks.py:793
|
||||||
msgid "Uploaded book probably exists in the library, consider to change before upload new: "
|
msgid "Uploaded book probably exists in the library, consider to change before upload new: "
|
||||||
msgstr "Le fichier téléchargé existe probablement dans la librairie, veuillez le modifier avant de le télécharger de nouveau: "
|
msgstr "Le fichier téléchargé existe probablement dans la librairie, veuillez le modifier avant de le télécharger de nouveau: "
|
||||||
|
|
||||||
#: cps/editbooks.py:878
|
#: cps/editbooks.py:881
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Failed to Move Cover File %(file)s: %(error)s"
|
msgid "Failed to Move Cover File %(file)s: %(error)s"
|
||||||
msgstr "Impossible de déplacer le fichier de couverture %(file)s: %(error)s"
|
msgstr "Impossible de déplacer le fichier de couverture %(file)s: %(error)s"
|
||||||
|
|
||||||
#: cps/editbooks.py:889
|
#: cps/editbooks.py:892
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File %(file)s uploaded"
|
msgid "File %(file)s uploaded"
|
||||||
msgstr "Le fichier %(file)s a été téléchargé"
|
msgstr "Le fichier %(file)s a été téléchargé"
|
||||||
|
|
||||||
#: cps/editbooks.py:915
|
#: cps/editbooks.py:918
|
||||||
msgid "Source or destination format for conversion missing"
|
msgid "Source or destination format for conversion missing"
|
||||||
msgstr "Le format de conversion de la source ou de la destination est manquant"
|
msgstr "Le format de conversion de la source ou de la destination est manquant"
|
||||||
|
|
||||||
#: cps/editbooks.py:923
|
#: cps/editbooks.py:926
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Book successfully queued for converting to %(book_format)s"
|
msgid "Book successfully queued for converting to %(book_format)s"
|
||||||
msgstr "Le livre a été mis avec succès en file de traitement pour conversion vers %(book_format)s"
|
msgstr "Le livre a été mis avec succès en file de traitement pour conversion vers %(book_format)s"
|
||||||
|
|
||||||
#: cps/editbooks.py:927
|
#: cps/editbooks.py:930
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "There was an error converting this book: %(res)s"
|
msgid "There was an error converting this book: %(res)s"
|
||||||
msgstr "Une erreur est survenue au cours de la conversion du livre : %(res)s"
|
msgstr "Une erreur est survenue au cours de la conversion du livre : %(res)s"
|
||||||
@ -417,151 +417,151 @@ msgstr "La configuration de Google Drive n’est pas terminée, essayez de désa
|
|||||||
msgid "Callback domain is not verified, please follow steps to verify domain in google developer console"
|
msgid "Callback domain is not verified, please follow steps to verify domain in google developer console"
|
||||||
msgstr "Le domaine de retour d’appel (Callback domain) est non vérifié, veuillez suivre les étapes nécessaires pour vérifier le domaine dans la console de développement de Google"
|
msgstr "Le domaine de retour d’appel (Callback domain) est non vérifié, veuillez suivre les étapes nécessaires pour vérifier le domaine dans la console de développement de Google"
|
||||||
|
|
||||||
#: cps/helper.py:79
|
#: cps/helper.py:82
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(format)s format not found for book id: %(book)d"
|
msgid "%(format)s format not found for book id: %(book)d"
|
||||||
msgstr "le format %(format)s est introuvable pour le livre : %(book)d"
|
msgstr "le format %(format)s est introuvable pour le livre : %(book)d"
|
||||||
|
|
||||||
#: cps/helper.py:85 cps/tasks/convert.py:50
|
#: cps/helper.py:88 cps/tasks/convert.py:50
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(format)s not found on Google Drive: %(fn)s"
|
msgid "%(format)s not found on Google Drive: %(fn)s"
|
||||||
msgstr "le %(format)s est introuvable sur Google Drive : %(fn)s"
|
msgstr "le %(format)s est introuvable sur Google Drive : %(fn)s"
|
||||||
|
|
||||||
#: cps/helper.py:90
|
#: cps/helper.py:93
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(format)s not found: %(fn)s"
|
msgid "%(format)s not found: %(fn)s"
|
||||||
msgstr "%(format)s introuvable : %(fn)s"
|
msgstr "%(format)s introuvable : %(fn)s"
|
||||||
|
|
||||||
#: cps/helper.py:95 cps/helper.py:228 cps/templates/detail.html:41
|
#: cps/helper.py:98 cps/helper.py:231 cps/templates/detail.html:41
|
||||||
#: cps/templates/detail.html:45
|
#: cps/templates/detail.html:45
|
||||||
msgid "Send to Kindle"
|
msgid "Send to Kindle"
|
||||||
msgstr "Envoyer vers Kindle"
|
msgstr "Envoyer vers Kindle"
|
||||||
|
|
||||||
#: cps/helper.py:96 cps/helper.py:112 cps/helper.py:230
|
#: cps/helper.py:99 cps/helper.py:115 cps/helper.py:233
|
||||||
msgid "This e-mail has been sent via Calibre-Web."
|
msgid "This e-mail has been sent via Calibre-Web."
|
||||||
msgstr "Ce courriel a été envoyé depuis Calibre-Web."
|
msgstr "Ce courriel a été envoyé depuis Calibre-Web."
|
||||||
|
|
||||||
#: cps/helper.py:110
|
#: cps/helper.py:113
|
||||||
msgid "Calibre-Web test e-mail"
|
msgid "Calibre-Web test e-mail"
|
||||||
msgstr "Courriel de test de Calibre-Web"
|
msgstr "Courriel de test de Calibre-Web"
|
||||||
|
|
||||||
#: cps/helper.py:111
|
#: cps/helper.py:114
|
||||||
msgid "Test e-mail"
|
msgid "Test e-mail"
|
||||||
msgstr "Courriel de test"
|
msgstr "Courriel de test"
|
||||||
|
|
||||||
#: cps/helper.py:128
|
#: cps/helper.py:131
|
||||||
msgid "Get Started with Calibre-Web"
|
msgid "Get Started with Calibre-Web"
|
||||||
msgstr "Bien démarrer avec Calibre-Web"
|
msgstr "Bien démarrer avec Calibre-Web"
|
||||||
|
|
||||||
#: cps/helper.py:133
|
#: cps/helper.py:136
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Registration e-mail for user: %(name)s"
|
msgid "Registration e-mail for user: %(name)s"
|
||||||
msgstr "Courriel d’inscription pour l’utilisateur : %(name)s"
|
msgstr "Courriel d’inscription pour l’utilisateur : %(name)s"
|
||||||
|
|
||||||
#: cps/helper.py:153 cps/helper.py:157 cps/helper.py:161 cps/helper.py:170
|
#: cps/helper.py:156 cps/helper.py:160 cps/helper.py:164 cps/helper.py:173
|
||||||
#: cps/helper.py:174 cps/helper.py:178
|
#: cps/helper.py:177 cps/helper.py:181
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Send %(format)s to Kindle"
|
msgid "Send %(format)s to Kindle"
|
||||||
msgstr "Envoyer %(format)s vers le Kindle"
|
msgstr "Envoyer %(format)s vers le Kindle"
|
||||||
|
|
||||||
#: cps/helper.py:183 cps/helper.py:189
|
#: cps/helper.py:186 cps/helper.py:192
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Convert %(orig)s to %(format)s and send to Kindle"
|
msgid "Convert %(orig)s to %(format)s and send to Kindle"
|
||||||
msgstr "Convertir de %(orig)s vers %(format)s et envoyer au Kindle"
|
msgstr "Convertir de %(orig)s vers %(format)s et envoyer au Kindle"
|
||||||
|
|
||||||
#: cps/helper.py:230
|
#: cps/helper.py:233
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "E-mail: %(book)s"
|
msgid "E-mail: %(book)s"
|
||||||
msgstr "Courriel : %(book)s"
|
msgstr "Courriel : %(book)s"
|
||||||
|
|
||||||
#: cps/helper.py:232
|
#: cps/helper.py:235
|
||||||
msgid "The requested file could not be read. Maybe wrong permissions?"
|
msgid "The requested file could not be read. Maybe wrong permissions?"
|
||||||
msgstr "Le fichier demandé n’a pu être lu. Problème de permission d’accès ?"
|
msgstr "Le fichier demandé n’a pu être lu. Problème de permission d’accès ?"
|
||||||
|
|
||||||
#: cps/helper.py:329
|
#: cps/helper.py:332
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s"
|
msgid "Deleting bookfolder for book %(id)s failed, path has subfolders: %(path)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cps/helper.py:335
|
#: cps/helper.py:338
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Deleting book %(id)s failed: %(message)s"
|
msgid "Deleting book %(id)s failed: %(message)s"
|
||||||
msgstr "La suppression du livre %(id)s a échoué: %(message)s"
|
msgstr "La suppression du livre %(id)s a échoué: %(message)s"
|
||||||
|
|
||||||
#: cps/helper.py:345
|
#: cps/helper.py:348
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Deleting book %(id)s, book path not valid: %(path)s"
|
msgid "Deleting book %(id)s, book path not valid: %(path)s"
|
||||||
msgstr "Suppression du livre %(id)s, le chemin du livre est invalide : %(path)s"
|
msgstr "Suppression du livre %(id)s, le chemin du livre est invalide : %(path)s"
|
||||||
|
|
||||||
#: cps/helper.py:400
|
#: cps/helper.py:403
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s"
|
msgid "Rename title from: '%(src)s' to '%(dest)s' failed with error: %(error)s"
|
||||||
msgstr "Renommer le titre de : '%(src)s' à '%(dest)s' a échoué avec l’erreur : %(error)s"
|
msgstr "Renommer le titre de : '%(src)s' à '%(dest)s' a échoué avec l’erreur : %(error)s"
|
||||||
|
|
||||||
#: cps/helper.py:415
|
#: cps/helper.py:418
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s"
|
msgid "Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s"
|
||||||
msgstr "La modification du nom de fichier du chemin : '%(src)s' vers '%(dest)s' a échoué avec l’erreur : %(error)s"
|
msgstr "La modification du nom de fichier du chemin : '%(src)s' vers '%(dest)s' a échoué avec l’erreur : %(error)s"
|
||||||
|
|
||||||
#: cps/helper.py:440 cps/helper.py:450 cps/helper.py:458
|
#: cps/helper.py:443 cps/helper.py:453 cps/helper.py:461
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "File %(file)s not found on Google Drive"
|
msgid "File %(file)s not found on Google Drive"
|
||||||
msgstr "Le fichier %(file)s n'a pas été trouvé dans Google Drive"
|
msgstr "Le fichier %(file)s n'a pas été trouvé dans Google Drive"
|
||||||
|
|
||||||
#: cps/helper.py:479
|
#: cps/helper.py:482
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Book path %(path)s not found on Google Drive"
|
msgid "Book path %(path)s not found on Google Drive"
|
||||||
msgstr "Le chemin du livre %(path)s n'a pas été trouvé dans Google Drive"
|
msgstr "Le chemin du livre %(path)s n'a pas été trouvé dans Google Drive"
|
||||||
|
|
||||||
#: cps/helper.py:588
|
#: cps/helper.py:591
|
||||||
msgid "Error Downloading Cover"
|
msgid "Error Downloading Cover"
|
||||||
msgstr "Erreur lors du téléchargement de la couverture"
|
msgstr "Erreur lors du téléchargement de la couverture"
|
||||||
|
|
||||||
#: cps/helper.py:591
|
#: cps/helper.py:594
|
||||||
msgid "Cover Format Error"
|
msgid "Cover Format Error"
|
||||||
msgstr "Erreur de format de couverture"
|
msgstr "Erreur de format de couverture"
|
||||||
|
|
||||||
#: cps/helper.py:606
|
#: cps/helper.py:609
|
||||||
msgid "Failed to create path for cover"
|
msgid "Failed to create path for cover"
|
||||||
msgstr "Impossible de créer le chemin pour la couverture"
|
msgstr "Impossible de créer le chemin pour la couverture"
|
||||||
|
|
||||||
#: cps/helper.py:611
|
#: cps/helper.py:614
|
||||||
msgid "Cover-file is not a valid image file, or could not be stored"
|
msgid "Cover-file is not a valid image file, or could not be stored"
|
||||||
msgstr "Le fichier couverture n'est pas un fichier image valide, ou ne peut pas être stocké"
|
msgstr "Le fichier couverture n'est pas un fichier image valide, ou ne peut pas être stocké"
|
||||||
|
|
||||||
#: cps/helper.py:622
|
#: cps/helper.py:625
|
||||||
msgid "Only jpg/jpeg/png/webp files are supported as coverfile"
|
msgid "Only jpg/jpeg/png/webp files are supported as coverfile"
|
||||||
msgstr "Seuls les fichiers jpg/jpeg/png/webp sont supportés comme fichier de couverture"
|
msgstr "Seuls les fichiers jpg/jpeg/png/webp sont supportés comme fichier de couverture"
|
||||||
|
|
||||||
#: cps/helper.py:636
|
#: cps/helper.py:639
|
||||||
msgid "Only jpg/jpeg files are supported as coverfile"
|
msgid "Only jpg/jpeg files are supported as coverfile"
|
||||||
msgstr "Seuls les fichiers jpg/jpeg sont supportés comme fichier de couverture"
|
msgstr "Seuls les fichiers jpg/jpeg sont supportés comme fichier de couverture"
|
||||||
|
|
||||||
#: cps/helper.py:684
|
#: cps/helper.py:687
|
||||||
msgid "Unrar binary file not found"
|
msgid "Unrar binary file not found"
|
||||||
msgstr "Fichier binaire Unrar non trouvé"
|
msgstr "Fichier binaire Unrar non trouvé"
|
||||||
|
|
||||||
#: cps/helper.py:698
|
#: cps/helper.py:701
|
||||||
msgid "Error excecuting UnRar"
|
msgid "Error excecuting UnRar"
|
||||||
msgstr "Une erreur est survenue lors de l'exécution d'UnRar"
|
msgstr "Une erreur est survenue lors de l'exécution d'UnRar"
|
||||||
|
|
||||||
#: cps/helper.py:747
|
#: cps/helper.py:750
|
||||||
msgid "Waiting"
|
msgid "Waiting"
|
||||||
msgstr "En attente"
|
msgstr "En attente"
|
||||||
|
|
||||||
#: cps/helper.py:749
|
#: cps/helper.py:752
|
||||||
msgid "Failed"
|
msgid "Failed"
|
||||||
msgstr "Echoué"
|
msgstr "Echoué"
|
||||||
|
|
||||||
#: cps/helper.py:751
|
#: cps/helper.py:754
|
||||||
msgid "Started"
|
msgid "Started"
|
||||||
msgstr "Débuté"
|
msgstr "Débuté"
|
||||||
|
|
||||||
#: cps/helper.py:753
|
#: cps/helper.py:756
|
||||||
msgid "Finished"
|
msgid "Finished"
|
||||||
msgstr "Terminé"
|
msgstr "Terminé"
|
||||||
|
|
||||||
#: cps/helper.py:755
|
#: cps/helper.py:758
|
||||||
msgid "Unknown Status"
|
msgid "Unknown Status"
|
||||||
msgstr "Statut inconnu"
|
msgstr "Statut inconnu"
|
||||||
|
|
||||||
@ -857,7 +857,7 @@ msgstr "Livres archivés"
|
|||||||
msgid "Show archived books"
|
msgid "Show archived books"
|
||||||
msgstr "Afficher les livres archivés"
|
msgstr "Afficher les livres archivés"
|
||||||
|
|
||||||
#: cps/ub.py:120
|
#: cps/ub.py:120 cps/web.py:1001
|
||||||
msgid "Books List"
|
msgid "Books List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -986,10 +986,6 @@ msgstr "Recherche avancée"
|
|||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Chercher"
|
msgstr "Chercher"
|
||||||
|
|
||||||
#: cps/web.py:1001
|
|
||||||
msgid "Books list"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: cps/web.py:1139
|
#: cps/web.py:1139
|
||||||
msgid "Ratings list"
|
msgid "Ratings list"
|
||||||
msgstr "Liste des évaluations"
|
msgstr "Liste des évaluations"
|
||||||
@ -1299,60 +1295,64 @@ msgstr "Éditer la configuration principale"
|
|||||||
msgid "Edit UI Configuration"
|
msgid "Edit UI Configuration"
|
||||||
msgstr "Configuration de l’interface utilisateur"
|
msgstr "Configuration de l’interface utilisateur"
|
||||||
|
|
||||||
#: cps/templates/admin.html:137
|
#: cps/templates/admin.html:136
|
||||||
msgid "Administration"
|
msgid "Administration"
|
||||||
msgstr "Administration"
|
msgstr "Administration"
|
||||||
|
|
||||||
|
#: cps/templates/admin.html:137
|
||||||
|
msgid "Download Debug Package"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: cps/templates/admin.html:138
|
#: cps/templates/admin.html:138
|
||||||
msgid "View Logs"
|
msgid "View Logs"
|
||||||
msgstr "Afficher les fichiers journaux"
|
msgstr "Afficher les fichiers journaux"
|
||||||
|
|
||||||
#: cps/templates/admin.html:139
|
#: cps/templates/admin.html:141
|
||||||
msgid "Reconnect Calibre Database"
|
msgid "Reconnect Calibre Database"
|
||||||
msgstr "Reconnecter la base de données Calibre"
|
msgstr "Reconnecter la base de données Calibre"
|
||||||
|
|
||||||
#: cps/templates/admin.html:140
|
#: cps/templates/admin.html:142
|
||||||
msgid "Restart"
|
msgid "Restart"
|
||||||
msgstr "Redémarrer Calibre-Web"
|
msgstr "Redémarrer Calibre-Web"
|
||||||
|
|
||||||
#: cps/templates/admin.html:141
|
#: cps/templates/admin.html:143
|
||||||
msgid "Shutdown"
|
msgid "Shutdown"
|
||||||
msgstr "Arrêter Calibre-Web"
|
msgstr "Arrêter Calibre-Web"
|
||||||
|
|
||||||
#: cps/templates/admin.html:147
|
#: cps/templates/admin.html:149
|
||||||
msgid "Update"
|
msgid "Update"
|
||||||
msgstr "Mise à jour de Calibre-Web"
|
msgstr "Mise à jour de Calibre-Web"
|
||||||
|
|
||||||
#: cps/templates/admin.html:151
|
#: cps/templates/admin.html:153
|
||||||
msgid "Version"
|
msgid "Version"
|
||||||
msgstr "Version"
|
msgstr "Version"
|
||||||
|
|
||||||
#: cps/templates/admin.html:152
|
#: cps/templates/admin.html:154
|
||||||
msgid "Details"
|
msgid "Details"
|
||||||
msgstr "Détails"
|
msgstr "Détails"
|
||||||
|
|
||||||
#: cps/templates/admin.html:158
|
#: cps/templates/admin.html:160
|
||||||
msgid "Current version"
|
msgid "Current version"
|
||||||
msgstr "Version actuelle"
|
msgstr "Version actuelle"
|
||||||
|
|
||||||
#: cps/templates/admin.html:164
|
#: cps/templates/admin.html:166
|
||||||
msgid "Check for Update"
|
msgid "Check for Update"
|
||||||
msgstr "Rechercher les mises à jour"
|
msgstr "Rechercher les mises à jour"
|
||||||
|
|
||||||
#: cps/templates/admin.html:165
|
#: cps/templates/admin.html:167
|
||||||
msgid "Perform Update"
|
msgid "Perform Update"
|
||||||
msgstr "Effectuer la mise à jour"
|
msgstr "Effectuer la mise à jour"
|
||||||
|
|
||||||
#: cps/templates/admin.html:177
|
#: cps/templates/admin.html:179
|
||||||
msgid "Are you sure you want to restart?"
|
msgid "Are you sure you want to restart?"
|
||||||
msgstr "Voulez-vous vraiment redémarrer Calibre-Web?"
|
msgstr "Voulez-vous vraiment redémarrer Calibre-Web?"
|
||||||
|
|
||||||
#: cps/templates/admin.html:182 cps/templates/admin.html:196
|
#: cps/templates/admin.html:184 cps/templates/admin.html:198
|
||||||
#: cps/templates/admin.html:216 cps/templates/shelf.html:80
|
#: cps/templates/admin.html:218 cps/templates/shelf.html:80
|
||||||
msgid "OK"
|
msgid "OK"
|
||||||
msgstr "OK"
|
msgstr "OK"
|
||||||
|
|
||||||
#: cps/templates/admin.html:183 cps/templates/admin.html:197
|
#: cps/templates/admin.html:185 cps/templates/admin.html:199
|
||||||
#: cps/templates/book_edit.html:192 cps/templates/book_table.html:84
|
#: cps/templates/book_edit.html:192 cps/templates/book_table.html:84
|
||||||
#: cps/templates/config_edit.html:391 cps/templates/config_view_edit.html:151
|
#: cps/templates/config_edit.html:391 cps/templates/config_view_edit.html:151
|
||||||
#: cps/templates/email_edit.html:47 cps/templates/email_edit.html:101
|
#: cps/templates/email_edit.html:47 cps/templates/email_edit.html:101
|
||||||
@ -1361,11 +1361,11 @@ msgstr "OK"
|
|||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuler"
|
msgstr "Annuler"
|
||||||
|
|
||||||
#: cps/templates/admin.html:195
|
#: cps/templates/admin.html:197
|
||||||
msgid "Are you sure you want to shutdown?"
|
msgid "Are you sure you want to shutdown?"
|
||||||
msgstr "Voulez-vous vraiment arrêter Calibre-Web?"
|
msgstr "Voulez-vous vraiment arrêter Calibre-Web?"
|
||||||
|
|
||||||
#: cps/templates/admin.html:207
|
#: cps/templates/admin.html:209
|
||||||
msgid "Updating, please do not reload this page"
|
msgid "Updating, please do not reload this page"
|
||||||
msgstr "Mise à jour en cours, ne pas rafraîchir la page"
|
msgstr "Mise à jour en cours, ne pas rafraîchir la page"
|
||||||
|
|
||||||
@ -2304,6 +2304,14 @@ msgstr "Le flux de sortie ne peut pas être affiché"
|
|||||||
msgid "Show Access Log: "
|
msgid "Show Access Log: "
|
||||||
msgstr "Afficher le journal d'accès : "
|
msgstr "Afficher le journal d'accès : "
|
||||||
|
|
||||||
|
#: cps/templates/logviewer.html:18
|
||||||
|
msgid "Download Calibre-Web Log"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: cps/templates/logviewer.html:21
|
||||||
|
msgid "Download Access Log"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: cps/templates/modal_dialogs.html:6
|
#: cps/templates/modal_dialogs.html:6
|
||||||
msgid "Select Allowed/Denied Tags"
|
msgid "Select Allowed/Denied Tags"
|
||||||
msgstr "Sélectionner les étiquettes autorisées/refusées"
|
msgstr "Sélectionner les étiquettes autorisées/refusées"
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
62
cps/web.py
62
cps/web.py
@ -323,31 +323,34 @@ def import_ldap_users():
|
|||||||
showtext['text'] = _(u'Error: No user returned in response of LDAP server')
|
showtext['text'] = _(u'Error: No user returned in response of LDAP server')
|
||||||
return json.dumps(showtext)
|
return json.dumps(showtext)
|
||||||
|
|
||||||
|
imported = 0
|
||||||
for username in new_users:
|
for username in new_users:
|
||||||
user = username.decode('utf-8')
|
user = username.decode('utf-8')
|
||||||
if '=' in user:
|
if '=' in user:
|
||||||
match = re.search("([a-zA-Z0-9-]+)=%s", config.config_ldap_user_object, re.IGNORECASE | re.UNICODE)
|
# if member object field is empty take user object as filter
|
||||||
if match:
|
try:
|
||||||
match_filter = match.group(1)
|
if config.config_ldap_member_user_object:
|
||||||
match = re.search(match_filter + "=([\d\s\w-]+)", user, re.IGNORECASE | re.UNICODE)
|
user_identifier = extract_user_identifier(user, config.config_ldap_member_user_object)
|
||||||
if match:
|
|
||||||
user = match.group(1)
|
|
||||||
else:
|
else:
|
||||||
log.warning("Could Not Parse LDAP User: %s", user)
|
user_identifier = extract_user_identifier(user, config.config_ldap_user_object)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log.warning(e)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
log.warning("Could Not Parse LDAP User: %s", user)
|
user_identifier = user
|
||||||
|
|
||||||
|
if ub.session.query(ub.User).filter(ub.User.nickname == user_identifier.lower()).first():
|
||||||
|
log.warning("LDAP User: %s Already in Database", user_identifier)
|
||||||
continue
|
continue
|
||||||
if ub.session.query(ub.User).filter(ub.User.nickname == user.lower()).first():
|
user_data = services.ldap.get_object_details(user=user_identifier,
|
||||||
log.warning("LDAP User: %s Already in Database", user)
|
|
||||||
continue
|
|
||||||
user_data = services.ldap.get_object_details(user=user,
|
|
||||||
group=None,
|
group=None,
|
||||||
query_filter=None,
|
query_filter=None,
|
||||||
dn_only=False)
|
dn_only=False)
|
||||||
if user_data:
|
if user_data:
|
||||||
content = ub.User()
|
content = ub.User()
|
||||||
content.nickname = user
|
# user_login_field = extract_dynamic_field_from_filter(user, config.config_ldap_user_object)
|
||||||
|
content.nickname = user_identifier # user_data[user_login_field][0].decode('utf-8')
|
||||||
content.password = '' # dummy password which will be replaced by ldap one
|
content.password = '' # dummy password which will be replaced by ldap one
|
||||||
if 'mail' in user_data:
|
if 'mail' in user_data:
|
||||||
content.email = user_data['mail'][0].decode('utf-8')
|
content.email = user_data['mail'][0].decode('utf-8')
|
||||||
@ -365,6 +368,7 @@ def import_ldap_users():
|
|||||||
ub.session.add(content)
|
ub.session.add(content)
|
||||||
try:
|
try:
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
|
imported +=1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning("Failed to create LDAP user: %s - %s", user, e)
|
log.warning("Failed to create LDAP user: %s - %s", user, e)
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
@ -373,10 +377,28 @@ def import_ldap_users():
|
|||||||
log.warning("LDAP User: %s Not Found", user)
|
log.warning("LDAP User: %s Not Found", user)
|
||||||
showtext['text'] = _(u'At Least One LDAP User Not Found in Database')
|
showtext['text'] = _(u'At Least One LDAP User Not Found in Database')
|
||||||
if not showtext:
|
if not showtext:
|
||||||
showtext['text'] = _(u'User Successfully Imported')
|
showtext['text'] = _(u'{} User Successfully Imported'.format(imported))
|
||||||
return json.dumps(showtext)
|
return json.dumps(showtext)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_user_data_from_field(user, field):
|
||||||
|
match = re.search(field + "=([\d\s\w-]+)", user, re.IGNORECASE | re.UNICODE)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
else:
|
||||||
|
raise Exception("Could Not Parse LDAP User: %s", user)
|
||||||
|
|
||||||
|
# CN=Firstname LastName,OU=Laba,OU=...,DC=...,DC=...
|
||||||
|
# CN=user displayname,OU=ouname1,OU=ouname2,OU=ouname3,DC=domain,DC=domain
|
||||||
|
def extract_user_identifier(user, filter):
|
||||||
|
match = re.search("([a-zA-Z0-9-]+)=%s", filter, re.IGNORECASE | re.UNICODE)
|
||||||
|
if match:
|
||||||
|
dynamic_field = match.group(1)
|
||||||
|
else:
|
||||||
|
raise Exception("Could Not Parse LDAP User: %s", user)
|
||||||
|
return extract_user_data_from_field(user, dynamic_field)
|
||||||
|
|
||||||
|
|
||||||
# ################################### data provider functions #########################################################
|
# ################################### data provider functions #########################################################
|
||||||
|
|
||||||
|
|
||||||
@ -631,6 +653,10 @@ def render_books_list(data, sort, book_id, page):
|
|||||||
order = [db.Books.author_sort.asc()]
|
order = [db.Books.author_sort.asc()]
|
||||||
if sort == 'authza':
|
if sort == 'authza':
|
||||||
order = [db.Books.author_sort.desc()]
|
order = [db.Books.author_sort.desc()]
|
||||||
|
if sort == 'seriesasc':
|
||||||
|
order = [db.Books.series_index.asc()]
|
||||||
|
if sort == 'seriesdesc':
|
||||||
|
order = [db.Books.series_index.desc()]
|
||||||
|
|
||||||
if data == "rated":
|
if data == "rated":
|
||||||
if current_user.check_visibility(constants.SIDEBAR_BEST_RATED):
|
if current_user.check_visibility(constants.SIDEBAR_BEST_RATED):
|
||||||
@ -813,7 +839,7 @@ def render_ratings_books(page, book_id, order):
|
|||||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||||
db.Books,
|
db.Books,
|
||||||
db.Books.ratings.any(db.Ratings.id == book_id),
|
db.Books.ratings.any(db.Ratings.id == book_id),
|
||||||
[db.Books.timestamp.desc(), order[0]])
|
[order[0]])
|
||||||
if name and name.rating <= 10:
|
if name and name.rating <= 10:
|
||||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||||
title=_(u"Rating: %(rating)s stars", rating=int(name.rating / 2)), page="ratings")
|
title=_(u"Rating: %(rating)s stars", rating=int(name.rating / 2)), page="ratings")
|
||||||
@ -827,7 +853,7 @@ def render_formats_books(page, book_id, order):
|
|||||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||||
db.Books,
|
db.Books,
|
||||||
db.Books.data.any(db.Data.format == book_id.upper()),
|
db.Books.data.any(db.Data.format == book_id.upper()),
|
||||||
[db.Books.timestamp.desc(), order[0]])
|
[order[0]])
|
||||||
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
|
||||||
title=_(u"File format: %(format)s", format=name.format), page="formats")
|
title=_(u"File format: %(format)s", format=name.format), page="formats")
|
||||||
else:
|
else:
|
||||||
@ -860,7 +886,7 @@ def render_language_books(page, name, order):
|
|||||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||||
db.Books,
|
db.Books,
|
||||||
db.Books.languages.any(db.Languages.lang_code == name),
|
db.Books.languages.any(db.Languages.lang_code == name),
|
||||||
[db.Books.timestamp.desc(), order[0]])
|
[order[0]])
|
||||||
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=name,
|
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=name,
|
||||||
title=_(u"Language: %(name)s", name=lang_name), page="language")
|
title=_(u"Language: %(name)s", name=lang_name), page="language")
|
||||||
|
|
||||||
@ -998,7 +1024,7 @@ def books_list(data, sort_param, book_id, page):
|
|||||||
@login_required
|
@login_required
|
||||||
def books_table():
|
def books_table():
|
||||||
visibility = current_user.view_settings.get('table', {})
|
visibility = current_user.view_settings.get('table', {})
|
||||||
return render_title_template('book_table.html', title=_(u"Books list"), page="book_table",
|
return render_title_template('book_table.html', title=_(u"Books List"), page="book_table",
|
||||||
visiblility=visibility)
|
visiblility=visibility)
|
||||||
|
|
||||||
@web.route("/ajax/listbooks")
|
@web.route("/ajax/listbooks")
|
||||||
|
400
messages.pot
400
messages.pot
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user