From 02bf821ad3b6454acc9010e84857f9ca0a63f700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20S=C3=A1nchez?= Date: Wed, 18 Sep 2024 10:29:23 +0100 Subject: [PATCH 1/4] Improve some english strings --- blackboard_sync/qt/LoginWebView.ui | 32 ++++++++++++++++++++++++---- blackboard_sync/qt/SettingsWindow.ui | 12 +++++------ blackboard_sync/qt/SetupWizard.ui | 4 ++-- blackboard_sync/qt/SyncTrayIcon.py | 6 +++--- blackboard_sync/qt/dialogs.py | 2 +- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/blackboard_sync/qt/LoginWebView.ui b/blackboard_sync/qt/LoginWebView.ui index 2f59dc3c..cc7dbcaf 100644 --- a/blackboard_sync/qt/LoginWebView.ui +++ b/blackboard_sync/qt/LoginWebView.ui @@ -17,7 +17,7 @@ - Log in to Blackboard + Log in to Blackboard Learn @@ -68,8 +68,15 @@ + + Go back + - ... + + + + + .. @@ -77,12 +84,22 @@ 24 + + Qt::NoArrow + + + Go to start + - ... + + + + + .. @@ -107,8 +124,15 @@ + + Report issue + - ... + + + + + .. diff --git a/blackboard_sync/qt/SettingsWindow.ui b/blackboard_sync/qt/SettingsWindow.ui index 4147786c..9f609b20 100644 --- a/blackboard_sync/qt/SettingsWindow.ui +++ b/blackboard_sync/qt/SettingsWindow.ui @@ -57,7 +57,7 @@ - Download Location + Download location @@ -89,7 +89,7 @@ - Change Location + Change location @@ -102,7 +102,7 @@ - Sync Every + Sync every @@ -143,7 +143,7 @@ - User Session + User session @@ -174,7 +174,7 @@ - Log Out + Log out @@ -187,7 +187,7 @@ - Initial Setup + Initial setup diff --git a/blackboard_sync/qt/SetupWizard.ui b/blackboard_sync/qt/SetupWizard.ui index 03227570..daa1908b 100644 --- a/blackboard_sync/qt/SetupWizard.ui +++ b/blackboard_sync/qt/SetupWizard.ui @@ -26,7 +26,7 @@ - BlackboardSync Setup + Setup @@ -54,7 +54,7 @@ - You are a few steps away from syncing your Blackboard content straight to your device! + You are a few steps away from syncing your Blackboard Learn content straight to your device! Qt::PlainText diff --git a/blackboard_sync/qt/SyncTrayIcon.py b/blackboard_sync/qt/SyncTrayIcon.py index 8d638a74..f38a0a47 100644 --- a/blackboard_sync/qt/SyncTrayIcon.py +++ b/blackboard_sync/qt/SyncTrayIcon.py @@ -64,7 +64,7 @@ def _init_ui(self) -> None: self._status.setEnabled(False) self.addAction(self._status) - self.reset_setup = QAction(tr("Redo Setup")) + self.reset_setup = QAction(tr("Setup")) self.addAction(self.reset_setup) self.quit = QAction(tr("Quit")) @@ -80,12 +80,12 @@ def set_logged_in(self, logged_in: bool) -> None: if logged_in: self.set_last_synced(self._last_synced) else: - self._status.setText(tr("Not Logged In")) + self._status.setText(tr("Not logged in")) def set_last_synced(self, last_synced: datetime | None) -> None: self._last_synced = last_synced human_ago = time_ago(last_synced) if last_synced else "Never" - self._status.setText(tr("Last Synced: ") + human_ago) + self._status.setText(tr("Last synced: ") + human_ago) def set_currently_syncing(self, syncing: bool) -> None: self.refresh.setEnabled(not syncing) diff --git a/blackboard_sync/qt/dialogs.py b/blackboard_sync/qt/dialogs.py index b6866112..f814b6d3 100644 --- a/blackboard_sync/qt/dialogs.py +++ b/blackboard_sync/qt/dialogs.py @@ -46,7 +46,7 @@ def __init__(self) -> None: def redownload_dialog(self) -> bool: q = QMessageBox() - q.setText(tr("Should BlackboardSync redownload all files?")) + q.setText(tr("Do you wish to redownload all files?")) q.setInformativeText(tr( "Answer no if you intend to move all past downloads manually" " (Recommended)." From 02980456f183632d48d840936c56aeb3413271d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20S=C3=A1nchez?= Date: Wed, 18 Sep 2024 10:29:53 +0100 Subject: [PATCH 2/4] Enable translation of last synced indicator --- blackboard_sync/qt/utils.py | 77 +++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/blackboard_sync/qt/utils.py b/blackboard_sync/qt/utils.py index 6fc2c8f0..b3a69724 100644 --- a/blackboard_sync/qt/utils.py +++ b/blackboard_sync/qt/utils.py @@ -23,7 +23,7 @@ from enum import IntEnum from datetime import datetime, timezone -from PyQt6.QtCore import QSettings +from PyQt6.QtCore import QSettings, QObject def open_in_file_browser(file: Path) -> None: @@ -66,26 +66,73 @@ def add_to_startup(app_id: str) -> None: settings.sync() +class Time(IntEnum): + SECOND = 1 + MINUTE = 60 + HOUR = MINUTE * 60 + DAY = HOUR * 24 + WEEK = DAY * 7 + MONTH = DAY * 30 + YEAR = DAY * 365 + + +class TimeStrings(QObject): + def get_name(self, unit: Time, plural: bool) -> str: + # it's not as simple as appending an 's' + if plural: + return self.get_plural_name(unit) + + match unit: + case Time.SECOND: + return self.tr("second") + case Time.MINUTE: + return self.tr("minute") + case Time.HOUR: + return self.tr("hour") + case Time.DAY: + return self.tr("day") + case Time.WEEK: + return self.tr("week") + case Time.MONTH: + return self.tr("month") + case Time.YEAR: + return self.tr("year") + + def get_plural_name(self, unit: Time) -> str: + match unit: + case Time.SECOND: + return self.tr("seconds") + case Time.MINUTE: + return self.tr("minutes") + case Time.HOUR: + return self.tr("hours") + case Time.DAY: + return self.tr("days") + case Time.WEEK: + return self.tr("weeks") + case Time.MONTH: + return self.tr("months") + case Time.YEAR: + return self.tr("years") + + @property + def template(self) -> str: + return self.tr("{n} {name} ago") + + @property + def suffix(self) -> str: + return self.tr("ago") + + def time_ago(timestamp: datetime) -> str: delta = datetime.now(tz=timezone.utc) - timestamp s = int(delta.total_seconds()) - class Time(IntEnum): - SECOND = 1 - MINUTE = 60 - HOUR = MINUTE * 60 - DAY = HOUR * 24 - WEEK = DAY * 7 - MONTH = DAY * 30 - YEAR = DAY * 365 - - def __str__(self) -> str: - return self.name.lower() - def get_human_time(seconds: int, unit: Time) -> str: n = seconds // unit - s = '' if n == 1 else 's' - return f"{n} {unit}{s} ago" + t = TimeStrings() + name = t.get_name(unit, n != 1) + return t.template.format(n=n, name=name) previous = Time.SECOND From 02eb46d75c303decc6d1a2732a1279237a652672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20S=C3=A1nchez?= Date: Wed, 18 Sep 2024 11:19:12 +0100 Subject: [PATCH 3/4] Use self.tr instead of QCoreApplication.translate --- blackboard_sync/qt/LoginWebView.py | 5 +---- blackboard_sync/qt/SettingsWindow.py | 6 ++++-- blackboard_sync/qt/SyncTrayIcon.py | 23 +++++++++-------------- blackboard_sync/qt/dialogs.py | 18 +++++++----------- blackboard_sync/qt/notification.py | 16 +++++++--------- blackboard_sync/qt/utils.py | 4 ---- 6 files changed, 28 insertions(+), 44 deletions(-) diff --git a/blackboard_sync/qt/LoginWebView.py b/blackboard_sync/qt/LoginWebView.py index f903751b..81d27b04 100644 --- a/blackboard_sync/qt/LoginWebView.py +++ b/blackboard_sync/qt/LoginWebView.py @@ -16,11 +16,9 @@ # MA 02110-1301, USA. import webbrowser -from functools import partial from threading import Timer from requests.cookies import RequestsCookieJar -from PyQt6.QtCore import QCoreApplication from PyQt6.QtCore import pyqtSlot, pyqtSignal, QObject, QUrl from PyQt6.QtWidgets import QWidget, QPushButton, QLabel from PyQt6.QtNetwork import QNetworkCookie @@ -30,7 +28,6 @@ from .assets import load_ui, get_theme_icon, AppIcon -tr = partial(QCoreApplication.translate, 'LoginWebView') WATCHDOG_DELAY = 30 @@ -125,7 +122,7 @@ def slot_help(self) -> None: webbrowser.open(self.help_url) def show_help(self) -> None: - self.status.setText(tr( + self.status.setText(self.tr( "Trouble logging in? Press the help button to let us know." )) self.help_button.setVisible(True) diff --git a/blackboard_sync/qt/SettingsWindow.py b/blackboard_sync/qt/SettingsWindow.py index 098b7c9c..dee1a2d3 100644 --- a/blackboard_sync/qt/SettingsWindow.py +++ b/blackboard_sync/qt/SettingsWindow.py @@ -103,6 +103,8 @@ def username(self) -> str: @username.setter def username(self, username: str) -> None: if username: - self.current_session_label.setText(f"Logged in as {username}") + self.current_session_label.setText( + self.tr("Logged in as ") + username) else: - self.current_session_label.setText("Not currently logged in") + self.current_session_label.setText( + self.tr("Not currently logged in")) diff --git a/blackboard_sync/qt/SyncTrayIcon.py b/blackboard_sync/qt/SyncTrayIcon.py index f38a0a47..1ba50208 100644 --- a/blackboard_sync/qt/SyncTrayIcon.py +++ b/blackboard_sync/qt/SyncTrayIcon.py @@ -15,21 +15,16 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. -from functools import partial from datetime import datetime from PyQt6.QtGui import QAction from PyQt6.QtCore import pyqtSignal, QObject from PyQt6.QtWidgets import QMenu, QSystemTrayIcon -from PyQt6.QtCore import QCoreApplication - from .assets import logo, get_theme_icon, AppIcon from .utils import time_ago from .notification import Event, TrayMessages -tr = partial(QCoreApplication.translate, 'SyncTrayMenu') - class SyncTrayMenu(QMenu): @@ -47,27 +42,27 @@ def _init_ui(self) -> None: close_icon = get_theme_icon(AppIcon.EXIT) open_dir_icon = get_theme_icon(AppIcon.OPEN) - self.refresh = QAction(tr("Sync now")) + self.refresh = QAction(self.tr("Sync now")) self.refresh.setIcon(sync_icon) self.addAction(self.refresh) - self.open_dir = QAction(tr("Open downloads")) + self.open_dir = QAction(self.tr("Open downloads")) self.open_dir.setIcon(open_dir_icon) self.addAction(self.open_dir) - self.preferences = QAction(tr("Preferences")) + self.preferences = QAction(self.tr("Preferences")) self.addAction(self.preferences) self.addSeparator() - self._status = QAction(tr("You haven't logged in")) + self._status = QAction(self.tr("You haven't logged in")) self._status.setEnabled(False) self.addAction(self._status) - self.reset_setup = QAction(tr("Setup")) + self.reset_setup = QAction(self.tr("Setup")) self.addAction(self.reset_setup) - self.quit = QAction(tr("Quit")) + self.quit = QAction(self.tr("Quit")) self.quit.setIcon(close_icon) self.addAction(self.quit) @@ -80,18 +75,18 @@ def set_logged_in(self, logged_in: bool) -> None: if logged_in: self.set_last_synced(self._last_synced) else: - self._status.setText(tr("Not logged in")) + self._status.setText(self.tr("Not logged in")) def set_last_synced(self, last_synced: datetime | None) -> None: self._last_synced = last_synced human_ago = time_ago(last_synced) if last_synced else "Never" - self._status.setText(tr("Last synced: ") + human_ago) + self._status.setText(self.tr("Last synced: ") + human_ago) def set_currently_syncing(self, syncing: bool) -> None: self.refresh.setEnabled(not syncing) if syncing: - self._status.setText(tr("Downloading now...")) + self._status.setText(self.tr("Downloading now...")) class SyncTrayIcon(QSystemTrayIcon): diff --git a/blackboard_sync/qt/dialogs.py b/blackboard_sync/qt/dialogs.py index f814b6d3..c54eca20 100644 --- a/blackboard_sync/qt/dialogs.py +++ b/blackboard_sync/qt/dialogs.py @@ -17,17 +17,13 @@ import webbrowser from pathlib import Path -from functools import partial -from PyQt6.QtCore import QCoreApplication, QObject +from PyQt6.QtCore import QObject from PyQt6.QtWidgets import QMessageBox, QFileDialog from .assets import logo -tr = partial(QCoreApplication.translate, 'Dialogs') - - class DirDialog(QFileDialog): """Open the file dialog in directory mode.""" def init(self) -> None: @@ -46,8 +42,8 @@ def __init__(self) -> None: def redownload_dialog(self) -> bool: q = QMessageBox() - q.setText(tr("Do you wish to redownload all files?")) - q.setInformativeText(tr( + q.setText(self.tr("Do you wish to redownload all files?")) + q.setInformativeText(self.tr( "Answer no if you intend to move all past downloads manually" " (Recommended)." )) @@ -61,10 +57,10 @@ def redownload_dialog(self) -> bool: def uni_not_supported_dialog(self, url: str) -> None: q = QMessageBox() - q.setText(tr( + q.setText(self.tr( "Unfortunately, your university is not yet supported" )) - q.setInformativeText(tr( + q.setInformativeText(self.tr( "You can help us provide support for it by visiting our website, " "which you can access by pressing the help button." )) @@ -79,10 +75,10 @@ def uni_not_supported_dialog(self, url: str) -> None: def login_error_dialog(self, url: str) -> None: q = QMessageBox() - q.setText(tr( + q.setText(self.tr( "There was an issue logging you in" )) - q.setInformativeText(tr( + q.setInformativeText(self.tr( "Please try again later, and if the error persists" " contact our support by pressing the button below." )) diff --git a/blackboard_sync/qt/notification.py b/blackboard_sync/qt/notification.py index 65f3a0cd..041cf5b4 100644 --- a/blackboard_sync/qt/notification.py +++ b/blackboard_sync/qt/notification.py @@ -15,13 +15,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. -from functools import partial from typing import NamedTuple from enum import Enum, IntEnum, auto from PyQt6.QtWidgets import QSystemTrayIcon -from PyQt6.QtCore import QCoreApplication, QObject -tr = partial(QCoreApplication.translate, 'TrayMessages') +from PyQt6.QtCore import QObject class Event(Enum): @@ -55,18 +53,18 @@ def __init__(self) -> None: self.messages = { Event.UPDATE_AVAILABLE: SyncTrayMsg( - tr('An update is available'), - tr('You can update the app from your digital store'), + self.tr('An update is available'), + self.tr('You can update the app from your digital store'), Severity.INFORMATION.value, Duration.SHORT ), Event.DOWNLOAD_ERROR: SyncTrayMsg( - tr('The download could not be completed'), - tr('There was an error while downloading your content'), + self.tr('The download could not be completed'), + self.tr('There was an error while downloading your content'), Severity.WARNING.value, Duration.LONG ), Event.APP_RUNNING: SyncTrayMsg( - tr('The app is running in the background'), - tr('Click the tray icon to manage your downloads'), + self.tr('The app is running in the background'), + self.tr('Click the tray icon to manage your downloads'), Severity.INFORMATION.value, Duration.LONG ) } diff --git a/blackboard_sync/qt/utils.py b/blackboard_sync/qt/utils.py index b3a69724..b863bdae 100644 --- a/blackboard_sync/qt/utils.py +++ b/blackboard_sync/qt/utils.py @@ -119,10 +119,6 @@ def get_plural_name(self, unit: Time) -> str: def template(self) -> str: return self.tr("{n} {name} ago") - @property - def suffix(self) -> str: - return self.tr("ago") - def time_ago(timestamp: datetime) -> str: delta = datetime.now(tz=timezone.utc) - timestamp From e34cb593cf96ab05c1405faaab7e6271b988619d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20S=C3=A1nchez?= Date: Wed, 18 Sep 2024 11:21:42 +0100 Subject: [PATCH 4/4] Update test strings --- tests/test_qt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_qt.py b/tests/test_qt.py index d34aca44..173c9db8 100644 --- a/tests/test_qt.py +++ b/tests/test_qt.py @@ -67,7 +67,7 @@ def _make_setup_wizard(institutions: list[str]): class TestSetupWizard: - intro = 'You are a few steps away from syncing your Blackboard content straight to your device!' + intro = 'You are a few steps away from syncing your Blackboard Learn content straight to your device!' uni_selection = 'First, tell us where you study' location_selection = 'Where do you want files to be downloaded?' page_number = 4 @@ -253,7 +253,7 @@ def test_settings_window_save_signal(self, qtbot, settings_window): class TestSyncTrayIcon: def test_tray_icon_initial_state(self, qtbot, tray_icon): - assert tray_icon._menu._status.text() == 'Not Logged In' + assert tray_icon._menu._status.text() == 'Not logged in' assert not tray_icon._menu.refresh.isVisible() assert not tray_icon._menu.preferences.isVisible() assert tray_icon._menu._status.isVisible() @@ -261,7 +261,7 @@ def test_tray_icon_initial_state(self, qtbot, tray_icon): def test_tray_icon_logged_in_state(self, qtbot, tray_icon): tray_icon.set_logged_in(True) - assert tray_icon._menu._status.text() != 'Not Logged In' + assert tray_icon._menu._status.text() != 'Not logged in' assert tray_icon._menu.refresh.isVisible() assert tray_icon._menu.refresh.isEnabled() assert tray_icon._menu.preferences.isVisible()