diff --git a/README.md b/README.md index 480a62c6..b66fd36d 100644 --- a/README.md +++ b/README.md @@ -118,16 +118,19 @@ flatpak install flathub io.github.slgobinath.SafeEyes Ensure to meet the following dependencies: - gir1.2-notify-0.7 +- gir1.2-gtk-4.0 - python3-babel - python3-croniter +- python3-gi - python3-psutil - python3-packaging - python3-xlib -- xprintidle (optional) -- wlrctl (wayland optional) +- python3-pywayland (optional for KDE/other wayland) +- xprintidle (optional for X11) +- wlrctl (optional for wayland/wlroots) - Python 3.10+ -**To install Safe Eyes:** +**To install Safe Eyes from PyPI:** ```bash sudo pip3 install safeeyes diff --git a/ruff.toml b/ruff.toml index 4724771d..3a8fcc03 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,8 +1,5 @@ target-version = "py310" -# gettext -builtins = ["_"] - [lint] select = ["E", "W", "F", "D2", "D3", "D4"] ignore = [ diff --git a/safeeyes/__main__.py b/safeeyes/__main__.py index e4e0d9f1..e8de3724 100755 --- a/safeeyes/__main__.py +++ b/safeeyes/__main__.py @@ -21,21 +21,18 @@ """ import argparse -import gettext -import locale import logging import signal import sys import psutil -from safeeyes import utility +from safeeyes import utility, translations +from safeeyes.translations import translate as _ from safeeyes.model import Config from safeeyes.safeeyes import SafeEyes from safeeyes.safeeyes import SAFE_EYES_VERSION from safeeyes.rpc import RPCClient -gettext.install("safeeyes", utility.LOCALE_PATH) - def __running(): """Check if SafeEyes is already running.""" @@ -68,21 +65,7 @@ def __running(): def main(): """Start the Safe Eyes.""" - system_locale = gettext.translation( - "safeeyes", - localedir=utility.LOCALE_PATH, - languages=[utility.system_locale(), "en_US"], - fallback=True, - ) - system_locale.install() - try: - # locale.bindtextdomain is required for Glade files - locale.bindtextdomain("safeeyes", utility.LOCALE_PATH) - except AttributeError: - logging.warning( - "installed python's gettext module does not support locale.bindtextdomain." - " locale.bindtextdomain is required for Glade files" - ) + system_locale = translations.setup() parser = argparse.ArgumentParser(prog="safeeyes") group = parser.add_mutually_exclusive_group() diff --git a/safeeyes/model.py b/safeeyes/model.py index d397ffb1..b19080f1 100644 --- a/safeeyes/model.py +++ b/safeeyes/model.py @@ -34,6 +34,7 @@ from gi.repository import Gtk from safeeyes import utility +from safeeyes.translations import translate as _ class Break: diff --git a/safeeyes/plugins/donotdisturb/dependency_checker.py b/safeeyes/plugins/donotdisturb/dependency_checker.py index 600cb2bf..96a00de4 100644 --- a/safeeyes/plugins/donotdisturb/dependency_checker.py +++ b/safeeyes/plugins/donotdisturb/dependency_checker.py @@ -17,6 +17,7 @@ # along with this program. If not, see . from safeeyes import utility +from safeeyes.translations import translate as _ def validate(plugin_config, plugin_settings): diff --git a/safeeyes/plugins/healthstats/dependency_checker.py b/safeeyes/plugins/healthstats/dependency_checker.py index daa3c942..475b535a 100644 --- a/safeeyes/plugins/healthstats/dependency_checker.py +++ b/safeeyes/plugins/healthstats/dependency_checker.py @@ -17,6 +17,7 @@ # along with this program. If not, see . from safeeyes import utility +from safeeyes.translations import translate as _ def validate(plugin_config, plugin_settings): diff --git a/safeeyes/plugins/healthstats/plugin.py b/safeeyes/plugins/healthstats/plugin.py index a1dc1f74..d5c0251c 100644 --- a/safeeyes/plugins/healthstats/plugin.py +++ b/safeeyes/plugins/healthstats/plugin.py @@ -21,6 +21,7 @@ import croniter import datetime import logging +from safeeyes.translations import translate as _ context = None session = None diff --git a/safeeyes/plugins/limitconsecutiveskipping/plugin.py b/safeeyes/plugins/limitconsecutiveskipping/plugin.py index 864b609e..16101bf9 100644 --- a/safeeyes/plugins/limitconsecutiveskipping/plugin.py +++ b/safeeyes/plugins/limitconsecutiveskipping/plugin.py @@ -19,6 +19,7 @@ """Limit how many breaks can be skipped or postponed in a row.""" import logging +from safeeyes.translations import translate as _ context = None no_of_skipped_breaks = 0 diff --git a/safeeyes/plugins/notification/plugin.py b/safeeyes/plugins/notification/plugin.py index 5dd4d51d..5c3a3d0b 100644 --- a/safeeyes/plugins/notification/plugin.py +++ b/safeeyes/plugins/notification/plugin.py @@ -20,6 +20,7 @@ import gi from safeeyes.model import BreakType +from safeeyes.translations import translate as _ gi.require_version("Notify", "0.7") from gi.repository import Notify diff --git a/safeeyes/plugins/smartpause/dependency_checker.py b/safeeyes/plugins/smartpause/dependency_checker.py index 6d9b7b29..c3df55d4 100644 --- a/safeeyes/plugins/smartpause/dependency_checker.py +++ b/safeeyes/plugins/smartpause/dependency_checker.py @@ -17,6 +17,7 @@ # along with this program. If not, see . from safeeyes import utility +from safeeyes.translations import translate as _ def validate(plugin_config, plugin_settings): diff --git a/safeeyes/plugins/trayicon/dependency_checker.py b/safeeyes/plugins/trayicon/dependency_checker.py index 2ea5d217..5febe594 100644 --- a/safeeyes/plugins/trayicon/dependency_checker.py +++ b/safeeyes/plugins/trayicon/dependency_checker.py @@ -18,6 +18,7 @@ from safeeyes import utility from safeeyes.model import PluginDependency +from safeeyes.translations import translate as _ import gi diff --git a/safeeyes/plugins/trayicon/plugin.py b/safeeyes/plugins/trayicon/plugin.py index 21ced707..fbbeb1bc 100644 --- a/safeeyes/plugins/trayicon/plugin.py +++ b/safeeyes/plugins/trayicon/plugin.py @@ -24,6 +24,7 @@ from gi.repository import Gio, GLib import logging from safeeyes import utility +from safeeyes.translations import translate as _ import threading import time import typing diff --git a/safeeyes/safeeyes.py b/safeeyes/safeeyes.py index d7f743ef..4ea5a93e 100644 --- a/safeeyes/safeeyes.py +++ b/safeeyes/safeeyes.py @@ -32,6 +32,7 @@ from safeeyes.ui.required_plugin_dialog import RequiredPluginDialog from safeeyes.model import State, RequiredPluginException from safeeyes.rpc import RPCServer +from safeeyes.translations import translate as _ from safeeyes.plugin_manager import PluginManager from safeeyes.core import SafeEyesCore from safeeyes.ui.settings_dialog import SettingsDialog diff --git a/safeeyes/translations.py b/safeeyes/translations.py new file mode 100644 index 00000000..f9ee344d --- /dev/null +++ b/safeeyes/translations.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# Safe Eyes is a utility to remind you to take break frequently +# to protect your eyes from eye strain. + +# Copyright (C) 2024 Mel Dafert + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +"""Translation setup and helpers.""" + +import locale +import logging +import gettext +from safeeyes import utility + +_translations = gettext.NullTranslations() + + +def setup(): + global _translations + _translations = gettext.translation( + "safeeyes", + localedir=utility.LOCALE_PATH, + languages=[utility.system_locale(), "en_US"], + fallback=True, + ) + try: + # locale.bindtextdomain is required for Glade files + locale.bindtextdomain("safeeyes", utility.LOCALE_PATH) + except AttributeError: + logging.warning( + "installed python's gettext module does not support locale.bindtextdomain." + " locale.bindtextdomain is required for Glade files" + ) + + return _translations + + +def translate(message: str) -> str: + """Translate the message using the current translator.""" + return _translations.gettext(message) diff --git a/safeeyes/ui/about_dialog.py b/safeeyes/ui/about_dialog.py index 62f3ed07..5914d44a 100644 --- a/safeeyes/ui/about_dialog.py +++ b/safeeyes/ui/about_dialog.py @@ -21,6 +21,7 @@ import os from safeeyes import utility +from safeeyes.translations import translate as _ ABOUT_DIALOG_GLADE = os.path.join(utility.BIN_DIRECTORY, "glade/about_dialog.glade") diff --git a/safeeyes/ui/break_screen.py b/safeeyes/ui/break_screen.py index 3ff43469..e74594a7 100644 --- a/safeeyes/ui/break_screen.py +++ b/safeeyes/ui/break_screen.py @@ -23,6 +23,7 @@ import gi from safeeyes import utility +from safeeyes.translations import translate as _ import Xlib from Xlib.display import Display from Xlib import X diff --git a/safeeyes/ui/required_plugin_dialog.py b/safeeyes/ui/required_plugin_dialog.py index 0c29decd..ebfbd5d7 100644 --- a/safeeyes/ui/required_plugin_dialog.py +++ b/safeeyes/ui/required_plugin_dialog.py @@ -24,6 +24,7 @@ from safeeyes import utility from safeeyes.model import PluginDependency +from safeeyes.translations import translate as _ REQUIRED_PLUGIN_DIALOG_GLADE = os.path.join( utility.BIN_DIRECTORY, "glade/required_plugin_dialog.glade" diff --git a/safeeyes/ui/settings_dialog.py b/safeeyes/ui/settings_dialog.py index 03adf447..1189d109 100644 --- a/safeeyes/ui/settings_dialog.py +++ b/safeeyes/ui/settings_dialog.py @@ -22,6 +22,7 @@ import gi from safeeyes import utility from safeeyes.model import Config, PluginDependency +from safeeyes.translations import translate as _ gi.require_version("Gtk", "4.0") from gi.repository import Gtk, Gio diff --git a/safeeyes/utility.py b/safeeyes/utility.py index 7ff5ec93..1ec4b601 100644 --- a/safeeyes/utility.py +++ b/safeeyes/utility.py @@ -46,6 +46,7 @@ from gi.repository import GLib from gi.repository import GdkPixbuf from packaging.version import parse +from safeeyes.translations import translate as _ BIN_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) HOME_DIRECTORY = os.environ.get("HOME") or os.path.expanduser("~") @@ -533,7 +534,7 @@ def initialize_platform(): logging.error("Failed to create desktop entry at %s" % desktop_entry) # Add links for all icons - for path, _, filenames in os.walk(SYSTEM_ICONS): + for path, _dirnames, filenames in os.walk(SYSTEM_ICONS): for filename in filenames: system_icon = os.path.join(path, filename) local_icon = os.path.join(