From 1e723dff3a70ca268657e9307dd60cfdab6e95f4 Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Sun, 24 Apr 2022 18:40:50 +0200 Subject: [PATCH] Make texts in Background thread translatable --- cps/about.py | 6 +++--- cps/converter.py | 9 +++++---- cps/editbooks.py | 7 ++++--- cps/helper.py | 12 +++++++----- cps/tasks/convert.py | 39 ++++++++++++++++++------------------- cps/tasks/database.py | 11 ++++------- cps/tasks/mail.py | 17 ++++++++-------- cps/tasks/thumbnail.py | 42 ++++++++++++++++++++-------------------- cps/tasks/upload.py | 9 ++++++--- cps/templates/stats.html | 2 +- 10 files changed, 78 insertions(+), 76 deletions(-) diff --git a/cps/about.py b/cps/about.py index 8f2bf715..92dc41aa 100644 --- a/cps/about.py +++ b/cps/about.py @@ -69,9 +69,9 @@ _VERSIONS.update(uploader.get_versions(False)) def collect_stats(): - _VERSIONS['ebook converter'] = _(converter.get_calibre_version()) - _VERSIONS['unrar'] = _(converter.get_unrar_version()) - _VERSIONS['kepubify'] = _(converter.get_kepubify_version()) + _VERSIONS['ebook converter'] = converter.get_calibre_version() + _VERSIONS['unrar'] = converter.get_unrar_version() + _VERSIONS['kepubify'] = converter.get_kepubify_version() return _VERSIONS diff --git a/cps/converter.py b/cps/converter.py index bb197467..af2a6c09 100644 --- a/cps/converter.py +++ b/cps/converter.py @@ -18,7 +18,8 @@ import os import re -from flask_babel import gettext as _ + +from flask_babel import lazy_gettext as N_ from . import config, logger from .subproc_wrapper import process_wait @@ -26,9 +27,9 @@ from .subproc_wrapper import process_wait log = logger.create() -# _() necessary to make babel aware of string for translation -_NOT_INSTALLED = _('not installed') -_EXECUTION_ERROR = _('Execution permissions missing') +# strings getting translated when used +_NOT_INSTALLED = N_('not installed') +_EXECUTION_ERROR = N_('Execution permissions missing') def _get_command_version(path, pattern, argument=None): diff --git a/cps/editbooks.py b/cps/editbooks.py index eab79472..768f1830 100755 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -25,7 +25,7 @@ from datetime import datetime import json from shutil import copyfile from uuid import uuid4 -from markupsafe import escape +from markupsafe import escape # dependency of flask from functools import wraps try: @@ -35,6 +35,7 @@ except ImportError: from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response from flask_babel import gettext as _ +from flask_babel import lazy_gettext as N_ from flask_login import current_user, login_required from sqlalchemy.exc import OperationalError, IntegrityError # from sqlite3 import OperationalError as sqliteOperationalError @@ -681,7 +682,7 @@ def upload_single_file(file_request, book, book_id): # Queue uploader info link = '{}'.format(url_for('web.show_book', book_id=book.id), escape(book.title)) - upload_text = _(u"File format %(ext)s added to %(book)s", ext=file_ext.upper(), book=link) + upload_text = N_(u"File format %(ext)s added to %(book)s", ext=file_ext.upper(), book=link) WorkerThread.add(current_user.name, TaskUpload(upload_text, escape(book.title))) return uploader.process( @@ -1134,7 +1135,7 @@ def upload(): if error: flash(error, category="error") link = '{}'.format(url_for('web.show_book', book_id=book_id), escape(title)) - upload_text = _(u"File %(file)s uploaded", file=link) + upload_text = N_(u"File %(file)s uploaded", file=link) WorkerThread.add(current_user.name, TaskUpload(upload_text, escape(title))) helper.add_book_to_thumbnail_cache(book_id) diff --git a/cps/helper.py b/cps/helper.py index ea5820dd..5c532dba 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -33,6 +33,7 @@ from babel.dates import format_datetime from babel.units import format_unit from flask import send_from_directory, make_response, redirect, abort, url_for from flask_babel import gettext as _ +from flask_babel import lazy_gettext as N_ from flask_login import current_user from sqlalchemy.sql.expression import true, false, and_, or_, text, func from sqlalchemy.exc import InvalidRequestError, OperationalError @@ -53,7 +54,7 @@ except ImportError: from . import calibre_db, cli from .tasks.convert import TaskConvert -from . import logger, config, get_locale, db, ub, kobo_sync_status, fs +from . import logger, config, get_locale, db, ub, fs from . import gdriveutils as gd from .constants import STATIC_DIR as _STATIC_DIR, CACHE_TYPE_THUMBNAILS, THUMBNAIL_TYPE_COVER, THUMBNAIL_TYPE_SERIES from .subproc_wrapper import process_wait @@ -111,9 +112,10 @@ def convert_book_format(book_id, calibrepath, old_book_format, new_book_format, return None +# Texts are not lazy translated as they are supposed to get send out as is def send_test_mail(kindle_mail, user_name): WorkerThread.add(user_name, TaskEmail(_(u'Calibre-Web test e-mail'), None, None, - config.get_mail_settings(), kindle_mail, _(u"Test e-mail"), + config.get_mail_settings(), kindle_mail, N_(u"Test e-mail"), _(u'This e-mail has been sent via Calibre-Web.'))) return @@ -135,7 +137,7 @@ def send_registration_mail(e_mail, user_name, default_password, resend=False): attachment=None, settings=config.get_mail_settings(), recipient=e_mail, - taskMessage=_(u"Registration e-mail for user: %(name)s", name=user_name), + task_message=N_(u"Registration e-mail for user: %(name)s", name=user_name), text=txt )) return @@ -219,7 +221,7 @@ def send_mail(book_id, book_format, convert, kindle_mail, calibrepath, user_id): if entry.format.upper() == book_format.upper(): converted_file_name = entry.name + '.' + book_format.lower() link = '{}'.format(url_for('web.show_book', book_id=book_id), escape(book.title)) - email_text = _(u"%(book)s send to Kindle", book=link) + email_text = N_(u"%(book)s send to Kindle", book=link) WorkerThread.add(user_id, TaskEmail(_(u"Send to Kindle"), book.path, converted_file_name, config.get_mail_settings(), kindle_mail, email_text, _(u'This e-mail has been sent via Calibre-Web.'))) @@ -1012,7 +1014,7 @@ def render_task_status(tasklist): else: ret['status'] = _(u'Unknown Status') - ret['taskMessage'] = "{}: {}".format(_(task.name), task.message) if task.message else _(task.name) + ret['taskMessage'] = "{}: {}".format(task.name, task.message) if task.message else task.name ret['progress'] = "{} %".format(int(task.progress * 100)) ret['user'] = escape(user) # prevent xss diff --git a/cps/tasks/convert.py b/cps/tasks/convert.py index 028d7dbf..e65d314a 100644 --- a/cps/tasks/convert.py +++ b/cps/tasks/convert.py @@ -18,12 +18,12 @@ import os import re - from glob import glob from shutil import copyfile from markupsafe import escape from sqlalchemy.exc import SQLAlchemyError +from flask_babel import lazy_gettext as N_ from cps.services.worker import CalibreTask from cps import db @@ -41,10 +41,10 @@ log = logger.create() class TaskConvert(CalibreTask): - def __init__(self, file_path, bookid, taskMessage, settings, kindle_mail, user=None): - super(TaskConvert, self).__init__(taskMessage) + def __init__(self, file_path, book_id, task_message, settings, kindle_mail, user=None): + super(TaskConvert, self).__init__(task_message) self.file_path = file_path - self.bookid = bookid + self.book_id = book_id self.title = "" self.settings = settings self.kindle_mail = kindle_mail @@ -56,9 +56,9 @@ class TaskConvert(CalibreTask): self.worker_thread = worker_thread if config.config_use_google_drive: worker_db = db.CalibreDB(expire_on_commit=False) - cur_book = worker_db.get_book(self.bookid) + cur_book = worker_db.get_book(self.book_id) self.title = cur_book.title - data = worker_db.get_book_format(self.bookid, self.settings['old_book_format']) + data = worker_db.get_book_format(self.book_id, self.settings['old_book_format']) df = gdriveutils.getFileFromEbooksFolder(cur_book.path, data.name + "." + self.settings['old_book_format'].lower()) if df: @@ -89,7 +89,7 @@ class TaskConvert(CalibreTask): # if we're sending to kindle after converting, create a one-off task and run it immediately # todo: figure out how to incorporate this into the progress try: - EmailText = _(u"%(book)s send to Kindle", book=escape(self.title)) + EmailText = N_(u"%(book)s send to Kindle", book=escape(self.title)) worker_thread.add(self.user, TaskEmail(self.settings['subject'], self.results["path"], filename, @@ -106,7 +106,7 @@ class TaskConvert(CalibreTask): error_message = None local_db = db.CalibreDB(expire_on_commit=False) file_path = self.file_path - book_id = self.bookid + book_id = self.book_id format_old_ext = u'.' + self.settings['old_book_format'].lower() format_new_ext = u'.' + self.settings['new_book_format'].lower() @@ -114,7 +114,7 @@ class TaskConvert(CalibreTask): # if it does - mark the conversion task as complete and return a success # this will allow send to kindle workflow to continue to work if os.path.isfile(file_path + format_new_ext) or\ - local_db.get_book_format(self.bookid, self.settings['new_book_format']): + local_db.get_book_format(self.book_id, self.settings['new_book_format']): log.info("Book id %d already converted to %s", book_id, format_new_ext) cur_book = local_db.get_book(book_id) self.title = cur_book.title @@ -133,7 +133,7 @@ class TaskConvert(CalibreTask): local_db.session.rollback() log.error("Database error: %s", e) local_db.session.close() - self._handleError(error_message) + self._handleError(N_("Database error: %(error)s.", error=e)) return self._handleSuccess() local_db.session.close() @@ -150,8 +150,7 @@ class TaskConvert(CalibreTask): else: # check if calibre converter-executable is existing if not os.path.exists(config.config_converterpath): - # ToDo Text is not translated - self._handleError(_(u"Calibre ebook-convert %(tool)s not found", tool=config.config_converterpath)) + self._handleError(N_(u"Calibre ebook-convert %(tool)s not found", tool=config.config_converterpath)) return check, error_message = self._convert_calibre(file_path, format_old_ext, format_new_ext) @@ -184,11 +183,11 @@ class TaskConvert(CalibreTask): self._handleSuccess() return os.path.basename(file_path + format_new_ext) else: - error_message = _('%(format)s format not found on disk', format=format_new_ext.upper()) + error_message = N_('%(format)s format not found on disk', format=format_new_ext.upper()) local_db.session.close() log.info("ebook converter failed with error while converting book") if not error_message: - error_message = _('Ebook converter failed with unknown error') + error_message = N_('Ebook converter failed with unknown error') self._handleError(error_message) return @@ -198,7 +197,7 @@ class TaskConvert(CalibreTask): try: p = process_open(command, quotes) except OSError as e: - return 1, _(u"Kepubify-converter failed: %(error)s", error=e) + return 1, N_(u"Kepubify-converter failed: %(error)s", error=e) self.progress = 0.01 while True: nextline = p.stdout.readlines() @@ -219,7 +218,7 @@ class TaskConvert(CalibreTask): copyfile(converted_file[0], (file_path + format_new_ext)) os.unlink(converted_file[0]) else: - return 1, _(u"Converted file not found or more than one file in folder %(folder)s", + return 1, N_(u"Converted file not found or more than one file in folder %(folder)s", folder=os.path.dirname(file_path)) return check, None @@ -243,7 +242,7 @@ class TaskConvert(CalibreTask): p = process_open(command, quotes, newlines=False) except OSError as e: - return 1, _(u"Ebook-converter failed: %(error)s", error=e) + return 1, N_(u"Ebook-converter failed: %(error)s", error=e) while p.poll() is None: nextline = p.stdout.readline() @@ -266,15 +265,15 @@ class TaskConvert(CalibreTask): ele = ele.decode('utf-8', errors="ignore").strip('\n') log.debug(ele) if not ele.startswith('Traceback') and not ele.startswith(' File'): - error_message = _("Calibre failed with error: %(error)s", error=ele) + error_message = N_("Calibre failed with error: %(error)s", error=ele) return check, error_message @property def name(self): - return "Convert" + return N_("Convert") def __str__(self): - return "Convert {} {}".format(self.bookid, self.kindle_mail) + return "Convert {} {}".format(self.book_id, self.kindle_mail) @property def is_cancellable(self): diff --git a/cps/tasks/database.py b/cps/tasks/database.py index 0441d564..6dd10f7c 100644 --- a/cps/tasks/database.py +++ b/cps/tasks/database.py @@ -16,19 +16,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from __future__ import division, print_function, unicode_literals +from urllib.request import urlopen + +from flask_babel import lazy_gettext as N_ from cps import config, logger from cps.services.worker import CalibreTask -try: - from urllib.request import urlopen -except ImportError as e: - from urllib2 import urlopen - class TaskReconnectDatabase(CalibreTask): - def __init__(self, task_message=u'Reconnecting Calibre database'): + def __init__(self, task_message=N_('Reconnecting Calibre database')): super(TaskReconnectDatabase, self).__init__(task_message) self.log = logger.create() self.listen_address = config.get_config_ipaddress() diff --git a/cps/tasks/mail.py b/cps/tasks/mail.py index 2a395634..ad38a400 100755 --- a/cps/tasks/mail.py +++ b/cps/tasks/mail.py @@ -26,9 +26,8 @@ from io import StringIO from email.message import EmailMessage from email.utils import parseaddr - -from email import encoders -from email.utils import formatdate, make_msgid +from flask_babel import lazy_gettext as N_ +from email.utils import formatdate from email.generator import Generator from cps.services.worker import CalibreTask @@ -111,13 +110,13 @@ class EmailSSL(EmailBase, smtplib.SMTP_SSL): class TaskEmail(CalibreTask): - def __init__(self, subject, filepath, attachment, settings, recipient, taskMessage, text, internal=False): - super(TaskEmail, self).__init__(taskMessage) + def __init__(self, subject, filepath, attachment, settings, recipient, task_message, text, internal=False): + super(TaskEmail, self).__init__(task_message) self.subject = subject self.attachment = attachment self.settings = settings self.filepath = filepath - self.recipent = recipient + self.recipient = recipient self.text = text self.asyncSMTP = None self.results = dict() @@ -139,7 +138,7 @@ class TaskEmail(CalibreTask): message = EmailMessage() # message = MIMEMultipart() message['From'] = self.settings["mail_from"] - message['To'] = self.recipent + message['To'] = self.recipient message['Subject'] = self.subject message['Date'] = formatdate(localtime=True) message['Message-Id'] = "{}@{}".format(uuid.uuid4(), self.get_msgid_domain()) # f"<{uuid.uuid4()}@{get_msgid_domain(from_)}>" # make_msgid('calibre-web') @@ -212,7 +211,7 @@ class TaskEmail(CalibreTask): gen = Generator(fp, mangle_from_=False) gen.flatten(msg) - self.asyncSMTP.sendmail(self.settings["mail_from"], self.recipent, fp.getvalue()) + self.asyncSMTP.sendmail(self.settings["mail_from"], self.recipient, fp.getvalue()) self.asyncSMTP.quit() self._handleSuccess() log.debug("E-mail send successfully") @@ -264,7 +263,7 @@ class TaskEmail(CalibreTask): @property def name(self): - return "E-mail" + return N_("E-mail") @property def is_cancellable(self): diff --git a/cps/tasks/thumbnail.py b/cps/tasks/thumbnail.py index f6015420..dcfd4226 100644 --- a/cps/tasks/thumbnail.py +++ b/cps/tasks/thumbnail.py @@ -24,7 +24,7 @@ from cps import config, db, fs, gdriveutils, logger, ub from cps.services.worker import CalibreTask, STAT_CANCELLED, STAT_ENDED from datetime import datetime from sqlalchemy import func, text, or_ - +from flask_babel import lazy_gettext as N_ try: from wand.image import Image @@ -92,7 +92,7 @@ class TaskGenerateCoverThumbnails(CalibreTask): if generated > 0: total_generated += generated - self.message = u'Generated {0} cover thumbnails'.format(total_generated) + self.message = N_(u'Generated %(count)s cover thumbnails', count=total_generated) # Check if job has been cancelled or ended if self.stat == STAT_CANCELLED: @@ -159,8 +159,8 @@ class TaskGenerateCoverThumbnails(CalibreTask): self.app_db_session.commit() self.generate_book_thumbnail(book, thumbnail) except Exception as ex: - self.log.info(u'Error creating book thumbnail: ' + str(ex)) - self._handleError(u'Error creating book thumbnail: ' + str(ex)) + self.log.info('Error creating book thumbnail: ' + str(ex)) + self._handleError('Error creating book thumbnail: ' + str(ex)) self.app_db_session.rollback() def update_book_cover_thumbnail(self, book, thumbnail): @@ -171,8 +171,8 @@ class TaskGenerateCoverThumbnails(CalibreTask): self.cache.delete_cache_file(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS) self.generate_book_thumbnail(book, thumbnail) except Exception as ex: - self.log.info(u'Error updating book thumbnail: ' + str(ex)) - self._handleError(u'Error updating book thumbnail: ' + str(ex)) + self.log.info('Error updating book thumbnail: ' + str(ex)) + self._handleError('Error updating book thumbnail: ' + str(ex)) self.app_db_session.rollback() def generate_book_thumbnail(self, book, thumbnail): @@ -199,7 +199,7 @@ class TaskGenerateCoverThumbnails(CalibreTask): img.save(filename=filename) except Exception as ex: # Bubble exception to calling function - self.log.info(u'Error generating thumbnail file: ' + str(ex)) + self.log.info('Error generating thumbnail file: ' + str(ex)) raise ex finally: if stream is not None: @@ -220,7 +220,7 @@ class TaskGenerateCoverThumbnails(CalibreTask): @property def name(self): - return 'Cover Thumbnails' + return N_('Cover Thumbnails') def __str__(self): if self.book_id > 0: @@ -279,7 +279,7 @@ class TaskGenerateSeriesThumbnails(CalibreTask): if generated > 0: total_generated += generated - self.message = u'Generated {0} series thumbnails'.format(total_generated) + self.message = N_('Generated {0} series thumbnails').format(total_generated) # Check if job has been cancelled or ended if self.stat == STAT_CANCELLED: @@ -335,8 +335,8 @@ class TaskGenerateSeriesThumbnails(CalibreTask): self.app_db_session.commit() self.generate_series_thumbnail(series_books, thumbnail) except Exception as ex: - self.log.info(u'Error creating book thumbnail: ' + str(ex)) - self._handleError(u'Error creating book thumbnail: ' + str(ex)) + self.log.info('Error creating book thumbnail: ' + str(ex)) + self._handleError('Error creating book thumbnail: ' + str(ex)) self.app_db_session.rollback() def update_series_thumbnail(self, series_books, thumbnail): @@ -347,8 +347,8 @@ class TaskGenerateSeriesThumbnails(CalibreTask): self.cache.delete_cache_file(thumbnail.filename, constants.CACHE_TYPE_THUMBNAILS) self.generate_series_thumbnail(series_books, thumbnail) except Exception as ex: - self.log.info(u'Error updating book thumbnail: ' + str(ex)) - self._handleError(u'Error updating book thumbnail: ' + str(ex)) + self.log.info('Error updating book thumbnail: ' + str(ex)) + self._handleError('Error updating book thumbnail: ' + str(ex)) self.app_db_session.rollback() def generate_series_thumbnail(self, series_books, thumbnail): @@ -391,7 +391,7 @@ class TaskGenerateSeriesThumbnails(CalibreTask): canvas.composite(img, left, top) except Exception as ex: - self.log.info(u'Error generating thumbnail file: ' + str(ex)) + self.log.info('Error generating thumbnail file: ' + str(ex)) raise ex finally: if stream is not None: @@ -433,7 +433,7 @@ class TaskGenerateSeriesThumbnails(CalibreTask): @property def name(self): - return 'Cover Thumbnails' + return N_('Cover Thumbnails') def __str__(self): return "GenerateSeriesThumbnails" @@ -444,7 +444,7 @@ class TaskGenerateSeriesThumbnails(CalibreTask): class TaskClearCoverThumbnailCache(CalibreTask): - def __init__(self, book_id, task_message=u'Clearing cover thumbnail cache'): + def __init__(self, book_id, task_message=N_('Clearing cover thumbnail cache')): super(TaskClearCoverThumbnailCache, self).__init__(task_message) self.log = logger.create() self.book_id = book_id @@ -486,8 +486,8 @@ class TaskClearCoverThumbnailCache(CalibreTask): .delete() self.app_db_session.commit() except Exception as ex: - self.log.info(u'Error deleting book thumbnail: ' + str(ex)) - self._handleError(u'Error deleting book thumbnail: ' + str(ex)) + self.log.info('Error deleting book thumbnail: ' + str(ex)) + self._handleError('Error deleting book thumbnail: ' + str(ex)) def delete_all_thumbnails(self): try: @@ -495,12 +495,12 @@ class TaskClearCoverThumbnailCache(CalibreTask): self.app_db_session.commit() self.cache.delete_cache_dir(constants.CACHE_TYPE_THUMBNAILS) except Exception as ex: - self.log.info(u'Error deleting thumbnail directory: ' + str(ex)) - self._handleError(u'Error deleting thumbnail directory: ' + str(ex)) + self.log.info('Error deleting thumbnail directory: ' + str(ex)) + self._handleError('Error deleting thumbnail directory: ' + str(ex)) @property def name(self): - return 'Cover Thumbnails' + return N_('Cover Thumbnails') # needed for logging def __str__(self): diff --git a/cps/tasks/upload.py b/cps/tasks/upload.py index cf5a64ac..bc8ba1e0 100644 --- a/cps/tasks/upload.py +++ b/cps/tasks/upload.py @@ -17,11 +17,14 @@ # along with this program. If not, see . from datetime import datetime + +from flask_babel import lazy_gettext as N_ + from cps.services.worker import CalibreTask, STAT_FINISH_SUCCESS class TaskUpload(CalibreTask): - def __init__(self, taskMessage, book_title): - super(TaskUpload, self).__init__(taskMessage) + def __init__(self, task_message, book_title): + super(TaskUpload, self).__init__(task_message) self.start_time = self.end_time = datetime.now() self.stat = STAT_FINISH_SUCCESS self.progress = 1 @@ -32,7 +35,7 @@ class TaskUpload(CalibreTask): @property def name(self): - return "Upload" + return N_("Upload") def __str__(self): return "Upload {}".format(self.book_title) diff --git a/cps/templates/stats.html b/cps/templates/stats.html index 052c920a..62a29308 100644 --- a/cps/templates/stats.html +++ b/cps/templates/stats.html @@ -39,7 +39,7 @@ {% if version %} {{library}} - {{_(version)}} + {{version}} {% endif %} {% endfor %}