diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 0476cfe4..11e34535 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -25,6 +25,8 @@ A clear and concise description of what you expected to happen. - Desktop Env [e.g. Gnome, KDE] - Version [e.g. 2.0.3] +**Flatpak issues**: If you experience any issue with flatpak, first please ensure that the bug is present in the [native package](https://github.com/slgobinath/SafeEyes?tab=readme-ov-file#installation-guide), and it is not a flatpak-only bug. Flatpak-only bugs should be reported at https://github.com/flathub/io.github.slgobinath.SafeEyes. (**Please erase this paragraph before creating the bug report**) + **Debug Log** Run the Safe Eyes using `safeeyes --debug` command attach the ~/safeeyes.log` file. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..9af2b10d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ +## Description + +Describe your changes here, and link to related issues if available. + +Reminder to run `python validate_po.py --extract` if you have added new translatable strings. diff --git a/README.md b/README.md index 68603b63..84e5871b 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Safe Eyes is available on the official repositories of many popular the distribu Packaging status -It is also available in Ubuntu PPA, Arch AUR, Gentoo and Python PyPI. You can choose any installation source and install on any Linux system with Python 3. +It is also available in Ubuntu PPA, Arch AUR and Python PyPI. You can choose any installation source and install on any Linux system with Python 3. ### Ubuntu, Linux Mint and other Ubuntu Derivatives @@ -79,13 +79,15 @@ sudo apt-get install safeeyes ``` ### Fedora - + If you want to use Smart Pause plugin, install the latest xprintidle from: [alonid/xprintidle](https://copr.fedorainfracloud.org/coprs/alonid/xprintidle/) ```bash sudo dnf install python3-psutil python3-packaging cairo-devel python3-devel gobject-introspection-devel cairo-gobject-devel sudo pip3 install safeeyes sudo gtk-update-icon-cache /usr/share/icons/hicolor ``` +We are looking for an official package maintainer for Fedora. Please [contact us](https://github.com/slgobinath/SafeEyes/issues/611) if you are interested. + ### OpenSUSE Tumbleweed ```bash @@ -100,7 +102,7 @@ sudo apk add safeeyes ``` ### Flatpak - +**Warning**: Many plugins and features don't work well in the flatpak. We recommend that you use one of the native packages listed above. Flatpak-only bugs should be reported at https://github.com/flathub/io.github.slgobinath.SafeEyes. ```bash flatpak install flathub io.github.slgobinath.SafeEyes ``` @@ -184,14 +186,22 @@ For more details, please check the issue: [#329](https://github.com/slgobinath/S Thirdparty plugins are available at another GitHub repository: [safeeyes-plugins](https://github.com/slgobinath/safeeyes-plugins). More details about how to write your own plugin and how to install third-party plugin are available there. +## Local development + +When adding new translatable strings in the source code, make sure to run `python validate_po.py --extract` to add them to the translation template. You will need to install `python3-polib` for this. + +Examples for translatable strings are `_("This is a string")` in Python code, or `This is a label` in Glade/xml files. + +To ensure the new strings are well-formed, you can use `python validate_po.py --validate`. + ## How to Release? 0. Run `update-po.sh` to generate new translation files (which will be eventually updated by translators). Commit and push the changes to the master branch. 1. Checkout the latest commits from the `master` branch 2. Run `python3 -m safeeyes` to make sure nothing is broken 3. Update the Safe Eyes version in the following places (Open the project in VSCode and search for the current version): - - [setup.py](https://github.com/slgobinath/SafeEyes/blob/master/setup.py#L83) - - [setup.py](https://github.com/slgobinath/SafeEyes/blob/master/setup.py#L90) + - [setup.py](https://github.com/slgobinath/SafeEyes/blob/master/setup.py#L82) + - [setup.py](https://github.com/slgobinath/SafeEyes/blob/master/setup.py#L89) - [safeeyes.py](https://github.com/slgobinath/SafeEyes/blob/master/safeeyes/safeeyes.py#L42) - [io.github.slgobinath.SafeEyes.metainfo.xml](https://github.com/slgobinath/SafeEyes/blob/master/safeeyes/platform/io.github.slgobinath.SafeEyes.metainfo.xml#L56) - [about_dialog.glade](https://github.com/slgobinath/SafeEyes/blob/master/safeeyes/glade/about_dialog.glade#L74) @@ -200,6 +210,12 @@ Thirdparty plugins are available at another GitHub repository: [safeeyes-plugins 6. Create a pull-request from `master` to `release` 7. Merge the PR to release **with merge commit** (Important to merge with merge commit) +## How you can help improving translation of Safe Eyes + +First check if translations for your language are already available on [Weblate](https://hosted.weblate.org/engage/safe-eyes/), which is the cloud based translation platform we use. + +- If the language is already there, feel free to add new translations or improve the existing ones. +- If it is not there, please [open an issue](https://github.com/slgobinath/SafeEyes/issues) in Github so that we can add your language to Weblate. ## License diff --git a/debian/changelog b/debian/changelog index e3691908..fadf0d8f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,24 @@ +safeeyes (2.2.3) jammy; urgency=medium + + * Translations + + * Make config and stylesheet files non-executable + + * Retry loading trayicon plugin to fix races on startup + + * Fix "Show next break time in tray icon" for desktops support tray icons + with labels + + * Fix next break time in tray icon when disabling SafeEyes + + * Make SafeEyes compatible with Python 3.6 again + + * Add 'hyprland' to the list of recognized desktop sessions + + * Remove hard dependency on X11 + + -- Mel Dafert Wed, 25 Dec 2024 11:46:00 +0000 + safeeyes (2.2.2) jammy; urgency=medium * Fixed translations diff --git a/safeeyes/config/locale/ar/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/ar/LC_MESSAGES/safeeyes.po index 50496bf5..64d6b798 100644 --- a/safeeyes/config/locale/ar/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/ar/LC_MESSAGES/safeeyes.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-07-26 11:09+0000\n" -"Last-Translator: RDWN IT \n" +"PO-Revision-Date: 2024-09-17 01:09+0000\n" +"Last-Translator: Barman Anonymous Please \n" "Language-Team: Arabic \n" "Language: ar\n" @@ -16,11 +16,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "أغمض عينيك بلطف" # Short break msgid "Roll your eyes a few times to each side" @@ -40,7 +40,7 @@ msgstr "اغمز بعينيك" # Short break msgid "Focus on a point in the far distance" -msgstr "ركّز على نقطة في المدى البعيد" +msgstr "ركّز على نقطة بعيدة" # Short break msgid "Have some water" @@ -76,7 +76,7 @@ msgstr "إظهار لوحة اﻹعدادات" # Commandline arg description msgid "start safeeyes in debug mode" -msgstr "ابدأ عيون سليمة في وضع التنقيح" +msgstr "ابدأ safeeyes في وضع التنقيح (debug)" # Commandline arg description msgid "print the status of running safeeyes instance and exit" @@ -109,7 +109,11 @@ msgstr "الرخصة" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "قائمة المساهمين" + +# About dialog +msgid "Help us translate this app" +msgstr "ساعدنا في ترجمة هذا التطبيق" # Break screen msgid "Skip" @@ -535,36 +539,36 @@ msgstr "أوقِف الوسائط" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "تقييد التخطي المتتالي" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "عدد مرات التخطي أو التأجيل المسموح بها على التوالي" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "حدد عدد فترات الاستراحة التي يمكن تخطيها أو تأجيلها على التوالي" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "تم تخطي أو تأجيل %(num)d/%(allowed)d من فترات الاستراحة على التوالي" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "الوقاية من الإصابات الناتجة عن الإجهاد المتكرر للعينين" msgid "" "Please install service providing tray icons for your desktop environment." -msgstr "" +msgstr "يرجى تثبيت خدمة توفر أيقونات في علبة النظام لبيئة سطح المكتب الخاصة بك." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "الاستراحة الطويلة القادمة في %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "الاستراحة القادمة في %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" diff --git a/safeeyes/config/locale/bg/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/bg/LC_MESSAGES/safeeyes.po index 0c86021d..81112bb8 100644 --- a/safeeyes/config/locale/bg/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/bg/LC_MESSAGES/safeeyes.po @@ -110,6 +110,10 @@ msgstr "Лиценз" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Пропускане" diff --git a/safeeyes/config/locale/bn/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/bn/LC_MESSAGES/safeeyes.po new file mode 100644 index 00000000..37e7b70e --- /dev/null +++ b/safeeyes/config/locale/bn/LC_MESSAGES/safeeyes.po @@ -0,0 +1,578 @@ +# SAFE EYES ENGLISH TRANSLATION. +# Copyright (C) 2017 Gobinath +# Gobinath slgobinath@gmail.com, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2024-08-16 15:09+0000\n" +"Last-Translator: Archisman Panigrahi \n" +"Language-Team: Bengali \n" +"Language: bn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n==0 || n==1);\n" +"X-Generator: Weblate 5.7\n" + +# Short break +msgid "Gently close your eyes" +msgstr "আলতো করে চোখ বন্ধ করুন" + +# Short break +msgid "Roll your eyes a few times to each side" +msgstr "" + +# Short break +msgid "Rotate your eyes in clockwise direction" +msgstr "" + +# Short break +msgid "Rotate your eyes in counterclockwise direction" +msgstr "" + +# Short break +msgid "Blink your eyes" +msgstr "" + +# Short break +msgid "Focus on a point in the far distance" +msgstr "" + +# Short break +msgid "Have some water" +msgstr "একটু জল খেয়ে নিন" + +# Long break +msgid "Walk for a while" +msgstr "একটু হেঁটে আসুন" + +# Long break +msgid "Lean back at your seat and relax" +msgstr "" + +# Commandline arg description +msgid "show the about dialog" +msgstr "" + +# Commandline arg description +msgid "disable the currently running safeeyes instance" +msgstr "" + +# Commandline arg description +msgid "enable the currently running safeeyes instance" +msgstr "" + +# Commandline arg description +msgid "quit the running safeeyes instance and exit" +msgstr "" + +# Commandline arg description +msgid "show the settings dialog" +msgstr "" + +# Commandline arg description +msgid "start safeeyes in debug mode" +msgstr "" + +# Commandline arg description +msgid "print the status of running safeeyes instance and exit" +msgstr "" + +# Status message +msgid "Safe Eyes is not running" +msgstr "Safe Eyes চলছে না" + +# RPC not enabled message +msgid "" +"Safe Eyes is running without an RPC server. Turn it on to use command-line " +"arguments." +msgstr "" + +# About dialog +msgid "Close" +msgstr "" + +# Description in about dialog +# Safe Eyes protects your eyes from eye strain (asthenopia) by reminding you to take breaks while you're working long hours at the computer +msgid "" +"Safe Eyes protects your eyes from eye strain (asthenopia) by reminding you " +"to take breaks while you're working long hours at the computer" +msgstr "" + +# About dialog +msgid "License" +msgstr "অনুমতিপত্র" + +# About dialog +msgid "List of Contributors" +msgstr "" + +# About dialog +msgid "Help us translate this app" +msgstr "" + +# Break screen +msgid "Skip" +msgstr "" + +# Break screen +msgid "Postpone" +msgstr "" + +# Settings dialog +msgid "Break duration (in seconds)" +msgstr "" + +# Settings dialog +msgid "Interval between two breaks (in minutes)" +msgstr "" + +# Settings dialog +msgid "Time to prepare for a break (in seconds)" +msgstr "" + +# Settings dialog +msgid "Keyboard shortcuts disabled period (in seconds)" +msgstr "" + +# Settings dialog +msgid "Postponement duration (in minutes)" +msgstr "" + +# Settings dialog +msgid "Show breaks in random order" +msgstr "" + +# Settings dialog +msgid "Strict break (No way to skip breaks)" +msgstr "" + +# Settings dialog +msgid "Allow postponing breaks" +msgstr "" + +# Settings dialog +msgid "Persist the internal state" +msgstr "" + +# Settings dialog +msgid "Use RPC server to receive runtime commands" +msgstr "" + +# Settings dialog +msgid "Without the RPC server, command-line commands may not work" +msgstr "" + +# Settings dialog +msgid "Long break interval must be a multiple of short break interval" +msgstr "" + +# Settings dialog +msgid "Reset" +msgstr "" + +# Settings dialog +msgid "Are you sure you want to reset all settings to default?" +msgstr "" + +# Settings dialog +msgid "Options" +msgstr "" + +# Settings dialog +msgid "Short Breaks" +msgstr "" + +# Settings dialog +msgid "Long Breaks" +msgstr "" + +# Settings dialog +msgid "Delete" +msgstr "" + +# Settings dialog +msgid "Are you sure you want to delete this break?" +msgstr "" + +# Settings dialog +msgid "You can't undo this action." +msgstr "" + +# Settings dialog +msgid "Break" +msgstr "" + +# Settings dialog +msgid "Breaks" +msgstr "" + +# Settings dialog +msgid "Plugins" +msgstr "" + +# Settings dialog +msgid "Type" +msgstr "" + +# Settings dialog +msgid "Short" +msgstr "" + +# Settings dialog +msgid "Long" +msgstr "" + +# Settings dialog +msgid "Image" +msgstr "" + +# Settings dialog +msgid "Select" +msgstr "" + +# Settings dialog +msgid "Please select an image" +msgstr "" + +# Settings dialog +msgid "Duration" +msgstr "" + +# Settings dialog +msgid "Time to wait" +msgstr "" + +# Settings dialog +msgid "Override" +msgstr "" + +# Settings dialog +msgid "Time (in seconds)" +msgstr "সময় (সেকেন্ডে)" + +# Settings dialog +msgid "Time (in minutes)" +msgstr "সময় (মিনিটে)" + +# Settings dialog +msgid "Break Settings" +msgstr "" + +# Settings dialog +msgid "Plugin Settings" +msgstr "" + +# Settings dialog +#, python-format +msgid "Plugin does not support %s desktop environment" +msgstr "" + +# Settings dialog +#, python-format +msgid "Please install the Python module '%s'" +msgstr "" + +# Settings dialog +#, python-format +msgid "Please install the command-line tool '%s'" +msgstr "" + +# Settings dialog +msgid "Invalid cron expression '%s'" +msgstr "" + +# Settings dialog +#, python-format +msgid "Please add the resource %(resource)s to %(config_resource)s directory" +msgstr "" + +# Settings dialog +msgid "New Break" +msgstr "" + +# Settings dialog +msgid "Remove" +msgstr "" + +# Settings dialog +msgid "Discard" +msgstr "" + +# Settings dialog +msgid "Save" +msgstr "" + +# plugin/audiblealert +msgid "Audible Alert" +msgstr "" + +# plugin/audiblealert +msgid "Play audible alert before and after breaks" +msgstr "" + +# plugin/audiblealert +msgid "Play audible alert before breaks" +msgstr "" + +# plugin/audiblealert +msgid "Play audible alert after breaks" +msgstr "" + +# plugin/donotdisturb +msgid "Do Not Disturb" +msgstr "" + +# plugin/donotdisturb +msgid "Skip break if the active window is in fullscreen mode" +msgstr "" + +# plugin/donotdisturb +msgid "Do not interrupt these windows anytime" +msgstr "" + +# plugin/donotdisturb +msgid "Interrupt these windows regardless of their state" +msgstr "" + +# plugin/donotdisturb +msgid "Switch the interruptible windows to normal mode" +msgstr "" + +# plugin/donotdisturb +msgid "Do not disturb while on battery" +msgstr "" + +# plugin/healthstats +msgid "Health Statistics" +msgstr "" + +# plugin/healthstats +msgid "Show statistics based on how you use Safe Eyes" +msgstr "" + +# plugin/healthstats +msgid "Statistics reset interval (cron expression)" +msgstr "" + +# plugin/notification +msgid "Notification" +msgstr "" + +# plugin/notification +msgid "Show a system notification before breaks" +msgstr "" + +# plugin/notification +#, python-format +msgid "Ready for a short break in %s seconds" +msgstr "" + +# plugin/notification +#, python-format +msgid "Ready for a long break in %s seconds" +msgstr "" + +# plugin/screensaver +msgid "Screensaver" +msgstr "" + +# plugin/screensaver +msgid "Lock the screen after long breaks by starting screensaver" +msgstr "" + +# plugin/screensaver +msgid "Custom screensaver command" +msgstr "" + +# plugin/screensaver +msgid "Minimum seconds to skip without screensaver" +msgstr "" + +# plugin/screensaver +msgid "Lock screen" +msgstr "" + +# plugin/smartpause +msgid "Smart Pause" +msgstr "" + +# plugin/smartpause +msgid "Pause Safe Eyes if the system is idle" +msgstr "" + +# plugin/smartpause +msgid "Minimum idle time to pause Safe Eyes (in seconds)" +msgstr "" + +# plugin/smartpause +msgid "Interpret idle time equivalent to upcoming break duration as a break" +msgstr "" + +# plugin/smartpause +msgid "Postpone the next break until the system becomes idle" +msgstr "" + +#: plugins/trayicon +msgid "Tray Icon" +msgstr "" + +#: plugins/trayicon +msgid "Show a tray icon in the notification area" +msgstr "" + +#: plugins/trayicon +msgid "Show next break time in tray icon" +msgstr "" + +#: plugins/trayicon +msgid "Allow disabling Safe Eyes" +msgstr "" + +#: plugins/trayicon +msgid "About" +msgstr "" + +#: plugins/trayicon +msgid "Disable Safe Eyes" +msgstr "" + +#: plugins/trayicon +#, python-format +msgid "Disabled until %s" +msgstr "" + +#: plugins/trayicon +msgid "Disabled until restart" +msgstr "" + +#: plugins/trayicon +msgid "Enable Safe Eyes" +msgstr "" + +#: plugins/trayicon +#, python-format +msgid "For %(num)d Hour" +msgid_plural "For %(num)d Hours" +msgstr[0] "" +msgstr[1] "" + +#: plugins/trayicon +#, python-format +msgid "For %(num)d Minute" +msgid_plural "For %(num)d Minutes" +msgstr[0] "" +msgstr[1] "" + +#: plugins/trayicon +#, python-format +msgid "For %(num)d Second" +msgid_plural "For %(num)d Seconds" +msgstr[0] "" +msgstr[1] "" + +#: plugins/trayicon +#, python-format +msgid "Next break at %s" +msgstr "" + +#: plugins/trayicon +msgid "No Breaks Available" +msgstr "" + +#: plugins/trayicon +msgid "Settings" +msgstr "" + +#: plugins/trayicon +msgid "Take a break now" +msgstr "" + +#: plugins/trayicon +msgid "Any break" +msgstr "" + +#: plugins/trayicon +msgid "Short break" +msgstr "" + +#: plugins/trayicon +msgid "Long break" +msgstr "" + +#: plugins/trayicon +msgid "Until restart" +msgstr "" + +#: plugins/trayicon +msgid "Quit" +msgstr "" + +# plugin/mediacontrol +msgid "Media Control" +msgstr "" + +# plugin/mediacontrol +msgid "Pause media players from the break screen" +msgstr "" + +# plugin/mediacontrol +msgid "Pause media" +msgstr "" + +# plugin/limitconsecutiveskipping +msgid "Limit Consecutive Skipping" +msgstr "" + +# plugin/limitconsecutiveskipping +msgid "How many skips or postpones are allowed in a row" +msgstr "" + +# plugin/limitconsecutiveskipping +msgid "Limit how many breaks can be skipped or postponed in a row" +msgstr "" + +# plugin/limitconsecutiveskipping +#, python-format +msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" +msgstr "" + +# safeeyes/platform/io.github.slgobinath.SafeEyes.desktop +msgid "RSI Prevention" +msgstr "" + +msgid "" +"Please install service providing tray icons for your desktop environment." +msgstr "" + +#, python-format +msgid "Next long break at %s" +msgstr "" + +#, python-format +msgid "Next breaks at %(short)s/%(long)s" +msgstr "" + +#, python-format +msgid "The required plugin '%s' is missing dependencies!" +msgstr "" + +msgid "" +"Please install the dependencies or disable the plugin. To hide this message, " +"you can also deactivate the plugin in the settings." +msgstr "" + +msgid "Click here for more information" +msgstr "" + +msgid "Disable plugin temporarily" +msgstr "" + +msgid "Disable permanently" +msgstr "" + +msgid "License:" +msgstr "" diff --git a/safeeyes/config/locale/ca/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/ca/LC_MESSAGES/safeeyes.po index 78468aac..1ec09e5d 100644 --- a/safeeyes/config/locale/ca/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/ca/LC_MESSAGES/safeeyes.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-08-08 21:25+0000\n" -"Last-Translator: calbasi \n" +"PO-Revision-Date: 2024-09-27 12:16+0000\n" +"Last-Translator: Andrés Martínez \n" "Language-Team: Catalan \n" "Language: ca\n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.14-dev\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Tanqueu els ulls suaument" # Short break msgid "Roll your eyes a few times to each side" @@ -90,6 +90,8 @@ msgid "" "Safe Eyes is running without an RPC server. Turn it on to use command-line " "arguments." msgstr "" +"Safe Eyes s'està executant sense un servidor RPC. Engegueu-lo per usar els " +"arguments de la línia de comandaments." # About dialog msgid "Close" @@ -111,7 +113,11 @@ msgstr "Llicència" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Llista de col·laboradors" + +# About dialog +msgid "Help us translate this app" +msgstr "Ajuda'ns a traduir aquesta aplicació" # Break screen msgid "Skip" @@ -135,7 +141,7 @@ msgstr "Temps per preparar-se per a una pausa (en segons)" # Settings dialog msgid "Keyboard shortcuts disabled period (in seconds)" -msgstr "" +msgstr "Període d'inhabilitació de les dreceres de teclat (en segons)" # Settings dialog msgid "Postponement duration (in minutes)" @@ -155,19 +161,21 @@ msgstr "Permet posposar les pauses" # Settings dialog msgid "Persist the internal state" -msgstr "" +msgstr "Persisteix l'estat intern" # Settings dialog msgid "Use RPC server to receive runtime commands" -msgstr "" +msgstr "Empra el servidor RPC per a rebre els comandaments del temps d'execució" # Settings dialog msgid "Without the RPC server, command-line commands may not work" -msgstr "" +msgstr "Sense el servidor RPC, és possible que els comandaments no funcionen" # Settings dialog msgid "Long break interval must be a multiple of short break interval" msgstr "" +"Cal que l'interval de pauses llargues siga múltiple de l'interval de pauses " +"curtes" # Settings dialog msgid "Reset" @@ -192,7 +200,7 @@ msgstr "Pauses llargues" # Settings dialog msgid "Delete" -msgstr "Suprimeix" +msgstr "Esborra" # Settings dialog msgid "Are you sure you want to delete this break?" @@ -236,7 +244,7 @@ msgstr "Trieu" # Settings dialog msgid "Please select an image" -msgstr "Si us plau, trieu una imatge" +msgstr "Trieu una imatge" # Settings dialog msgid "Duration" @@ -269,26 +277,26 @@ msgstr "Preferències del complement" # Settings dialog #, python-format msgid "Plugin does not support %s desktop environment" -msgstr "" +msgstr "El complement no admet l'entorn d'escriptori %s" # Settings dialog #, python-format msgid "Please install the Python module '%s'" -msgstr "" +msgstr "Instal·leu el mòdul de Python '%s'" # Settings dialog #, python-format msgid "Please install the command-line tool '%s'" -msgstr "" +msgstr "Instal·leu la ferramenta de la línia de comandament '%s'" # Settings dialog msgid "Invalid cron expression '%s'" -msgstr "" +msgstr "Expressió cron no vàlida '%s'" # Settings dialog #, python-format msgid "Please add the resource %(resource)s to %(config_resource)s directory" -msgstr "" +msgstr "Afegiu el recurs %(resource)s al directori %(config_resource)s" # Settings dialog msgid "New Break" @@ -312,15 +320,15 @@ msgstr "Alerta audible" # plugin/audiblealert msgid "Play audible alert before and after breaks" -msgstr "" +msgstr "Reprodueix una alerta audible abans i després de les pauses" # plugin/audiblealert msgid "Play audible alert before breaks" -msgstr "" +msgstr "Reprodueix una alerta audible abans de les pauses" # plugin/audiblealert msgid "Play audible alert after breaks" -msgstr "" +msgstr "Reprodueix una alerta audible després de les pauses" # plugin/donotdisturb msgid "Do Not Disturb" @@ -328,23 +336,23 @@ msgstr "No molesteu" # plugin/donotdisturb msgid "Skip break if the active window is in fullscreen mode" -msgstr "" +msgstr "Omet la pausa si la finestra activa està en mode pantalla completa" # plugin/donotdisturb msgid "Do not interrupt these windows anytime" -msgstr "" +msgstr "No interrompis aquestes finestres mai" # plugin/donotdisturb msgid "Interrupt these windows regardless of their state" -msgstr "" +msgstr "Interromp aquestes finestres independentment del seu estat" # plugin/donotdisturb msgid "Switch the interruptible windows to normal mode" -msgstr "" +msgstr "Canviar les finestres interruptibles al mode normal" # plugin/donotdisturb msgid "Do not disturb while on battery" -msgstr "" +msgstr "No molestar quan s'utilitza la bateria" # plugin/healthstats msgid "Health Statistics" @@ -352,24 +360,24 @@ msgstr "Estadístiques de salut" # plugin/healthstats msgid "Show statistics based on how you use Safe Eyes" -msgstr "" +msgstr "Mostra estadístiques de com useu Safe Eyes" # plugin/healthstats msgid "Statistics reset interval (cron expression)" -msgstr "" +msgstr "Interval de reinici de les estadístiques (expressió cron)" # plugin/notification msgid "Notification" -msgstr "" +msgstr "Notificació" # plugin/notification msgid "Show a system notification before breaks" -msgstr "" +msgstr "Mostra una notificació del sistema abans de les pauses" # plugin/notification #, python-format msgid "Ready for a short break in %s seconds" -msgstr "" +msgstr "Preparat per a una pausa breu en %s segons" # plugin/notification #, python-format diff --git a/safeeyes/config/locale/cs/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/cs/LC_MESSAGES/safeeyes.po index 2af07cc2..d166beba 100644 --- a/safeeyes/config/locale/cs/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/cs/LC_MESSAGES/safeeyes.po @@ -6,20 +6,20 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-10-31 16:04+0000\n" -"Last-Translator: Kryštof Jelínek \n" +"PO-Revision-Date: 2024-08-27 19:09+0000\n" +"Last-Translator: vikdevelop \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 5.2-dev\n" +"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" +"X-Generator: Weblate 5.7.1-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Jemně zavřete své oči" # Short break msgid "Roll your eyes a few times to each side" @@ -112,7 +112,11 @@ msgstr "Licence" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Seznam přispěvatelů" + +# About dialog +msgid "Help us translate this app" +msgstr "Pomozte nám přeložit tuto aplikaci" # Break screen msgid "Skip" @@ -499,15 +503,15 @@ msgstr "Udělat si přestávku" #: plugins/trayicon msgid "Any break" -msgstr "" +msgstr "Jakákoliv přestávka" #: plugins/trayicon msgid "Short break" -msgstr "" +msgstr "Krátká přestávka" #: plugins/trayicon msgid "Long break" -msgstr "" +msgstr "Dlouhá přestávka" #: plugins/trayicon msgid "Until restart" @@ -531,57 +535,61 @@ msgstr "Pozastavit média" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "Omezení po sobě jdoucích přeskočení" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "Kolik přeskočení nebo odložení je povoleno v řadě za sebou" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "Omezit počet přestávek, které lze vynechat nebo odložit za sebou" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "Vynechané nebo odložené %(num)d/%(allowed)d přestávky za sebou" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "Prevence poranění z opakovaného namáhání (RSI)" msgid "" "Please install service providing tray icons for your desktop environment." msgstr "" +"Nainstalujte prosím službu poskytující ikony na panelu pro vaše desktopové " +"prostředí." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "Další dlouhá přestávka za %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "Další přestávky za %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "Požadovanému zásuvnému modulu '%s' chybí závislosti!" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"Nainstalujte prosím požadované závislosti nebo zakažte tento zásuvný modul. " +"Pro skrytí této zprávy, můžete také deaktivovat zásuvný modul v nastavení." msgid "Click here for more information" -msgstr "" +msgstr "Klikněte zde pro více informací" msgid "Disable plugin temporarily" -msgstr "" +msgstr "Zakázat zásuvný modul dočasně" msgid "Disable permanently" -msgstr "" +msgstr "Zakázat permanentně" msgid "License:" -msgstr "" +msgstr "Licence:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/da/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/da/LC_MESSAGES/safeeyes.po index 8fddb464..eefa676e 100644 --- a/safeeyes/config/locale/da/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/da/LC_MESSAGES/safeeyes.po @@ -112,6 +112,10 @@ msgstr "Licens" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Spring over" diff --git a/safeeyes/config/locale/de/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/de/LC_MESSAGES/safeeyes.po index 52084f63..13eeadcd 100644 --- a/safeeyes/config/locale/de/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/de/LC_MESSAGES/safeeyes.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-07-28 15:09+0000\n" -"Last-Translator: Ettore Atalan \n" +"PO-Revision-Date: 2024-09-21 15:40+0000\n" +"Last-Translator: Erik Michelson \n" "Language-Team: German \n" "Language: de\n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Schließe sanft deine Augen" # Short break msgid "Roll your eyes a few times to each side" @@ -115,6 +115,10 @@ msgstr "Lizenz" msgid "List of Contributors" msgstr "Liste der Mitwirkenden" +# About dialog +msgid "Help us translate this app" +msgstr "Hilf mit die Anwendung zu übersetzen" + # Break screen msgid "Skip" msgstr "Überspringen" @@ -549,7 +553,8 @@ msgstr "" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "%(num)d/%(allowed)d Pausen hintereinander übersprungen oder aufgeschoben" +msgstr "" +"%(num)d/%(allowed)d Pausen hintereinander übersprungen oder aufgeschoben" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" @@ -591,7 +596,7 @@ msgid "Disable permanently" msgstr "Permanent ausschalten" msgid "License:" -msgstr "" +msgstr "Lizenz:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po index 18206b1b..dca10177 100644 --- a/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: 2017-09-17 07:59-0400\n" -"PO-Revision-Date: 2021-07-04 07:32+0000\n" -"Last-Translator: J. Lavoie \n" +"PO-Revision-Date: 2024-08-07 15:09+0000\n" +"Last-Translator: Archisman Panigrahi \n" "Language-Team: English (United States) \n" "Language: en_US\n" @@ -15,12 +15,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.8-dev\n" +"X-Generator: Weblate 5.7-dev\n" "Generated-By: pygettext.py 1.5\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Gently close your eyes" # Short break msgid "Roll your eyes a few times to each side" @@ -115,6 +115,10 @@ msgstr "License" msgid "List of Contributors" msgstr "List of Contributors" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Skip" diff --git a/safeeyes/config/locale/eo/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/eo/LC_MESSAGES/safeeyes.po index c59ff715..aea50168 100644 --- a/safeeyes/config/locale/eo/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/eo/LC_MESSAGES/safeeyes.po @@ -113,6 +113,10 @@ msgstr "Licenco" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Preterpasi" diff --git a/safeeyes/config/locale/es/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/es/LC_MESSAGES/safeeyes.po index ecdc2fce..d5da4c82 100644 --- a/safeeyes/config/locale/es/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/es/LC_MESSAGES/safeeyes.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-08-05 23:09+0000\n" +"PO-Revision-Date: 2024-09-02 07:09+0000\n" "Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Cierra los ojos suavemente" # Short break msgid "Roll your eyes a few times to each side" @@ -114,6 +114,10 @@ msgstr "Licencia" msgid "List of Contributors" msgstr "Colaboradores" +# About dialog +msgid "Help us translate this app" +msgstr "Ayúdanos a traducir esta aplicación" + # Break screen msgid "Skip" msgstr "Saltar" diff --git a/safeeyes/config/locale/et/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/et/LC_MESSAGES/safeeyes.po index fc11c99e..97276086 100644 --- a/safeeyes/config/locale/et/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/et/LC_MESSAGES/safeeyes.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-02-18 00:50+0000\n" -"Last-Translator: Kristjan Räts \n" +"PO-Revision-Date: 2024-11-12 23:00+0000\n" +"Last-Translator: Priit Jõerüüt \n" "Language-Team: Estonian \n" "Language: et\n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.5\n" +"X-Generator: Weblate 5.9-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Sulge õrnalt oma silmad" # Short break msgid "Roll your eyes a few times to each side" @@ -103,7 +103,7 @@ msgid "" "Safe Eyes protects your eyes from eye strain (asthenopia) by reminding you " "to take breaks while you're working long hours at the computer" msgstr "" -"Safe Eyes aitab vähendada arvutiga töötamisel silmade väsimust, tuletades " +"Safe Eyes aitab arvutiga töötamisel vähendada silmade väsimust, tuletades " "meelde puhkepause" # About dialog @@ -112,7 +112,11 @@ msgstr "Litsents" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Kaasautorite loend" + +# About dialog +msgid "Help us translate this app" +msgstr "Aita meil seda rakendust tõlkida" # Break screen msgid "Skip" @@ -124,7 +128,7 @@ msgstr "Lükka edasi" # Settings dialog msgid "Break duration (in seconds)" -msgstr "Pausi kestvus (sekundites)" +msgstr "Pausi kestus (sekundites)" # Settings dialog msgid "Interval between two breaks (in minutes)" @@ -240,7 +244,7 @@ msgstr "Palun vali pilt" # Settings dialog msgid "Duration" -msgstr "Kestvus" +msgstr "Kestus" # Settings dialog msgid "Time to wait" @@ -252,11 +256,11 @@ msgstr "Muuda vaikimisi seadeid" # Settings dialog msgid "Time (in seconds)" -msgstr "Kestvus (sekundites)" +msgstr "Kestus (sekundites)" # Settings dialog msgid "Time (in minutes)" -msgstr "Kestvus (minutites)" +msgstr "Kestus (minutites)" # Settings dialog msgid "Break Settings" @@ -493,15 +497,15 @@ msgstr "Tee nüüd paus" #: plugins/trayicon msgid "Any break" -msgstr "" +msgstr "Iga puhkepaus" #: plugins/trayicon msgid "Short break" -msgstr "" +msgstr "Lühike puhkepaus" #: plugins/trayicon msgid "Long break" -msgstr "" +msgstr "Pikk puhkepaus" #: plugins/trayicon msgid "Until restart" @@ -525,57 +529,61 @@ msgstr "Peata meedia" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "Piira järjest vahelejätmisi" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "Kui mitu edasilükkamist või vahelejätmist võid järjest teha" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "Kui mitu pausi võid järjest vahele jätta või edasi lükata" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "Järjest vahelejäetud või edasilükatatud %(num)d/%(allowed)d pausi" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "RSI ennetus" msgid "" "Please install service providing tray icons for your desktop environment." msgstr "" +"Palun paigalda teenus, mis võimaldab sinu töölauakeskkonnas kasutada " +"süsteemisalve." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "Järgmine pikk puhkepaus %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "Järgmised puhkepausid %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "Vajalikul „%s“ pluginal puuduvad sõltuvad komponendid!" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"Palun lisa vajalikud komponendid või lülita plugin välja. Viimast saad teha " +"seadistustest ja sellega ei teki enam ka antud teadet." msgid "Click here for more information" -msgstr "" +msgstr "Lisateabeks klõpsi siin" msgid "Disable plugin temporarily" -msgstr "" +msgstr "Lülita plugin ajutiselt välja" msgid "Disable permanently" -msgstr "" +msgstr "Lülita püsivalt välja" msgid "License:" -msgstr "" +msgstr "Litsents:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/eu/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/eu/LC_MESSAGES/safeeyes.po index 9cb9138e..399796f4 100644 --- a/safeeyes/config/locale/eu/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/eu/LC_MESSAGES/safeeyes.po @@ -114,6 +114,10 @@ msgstr "Lizentzia" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Saltatu" diff --git a/safeeyes/config/locale/fa/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/fa/LC_MESSAGES/safeeyes.po index 1eb96c89..817384ce 100644 --- a/safeeyes/config/locale/fa/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/fa/LC_MESSAGES/safeeyes.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-07-28 15:09+0000\n" -"Last-Translator: Parsa Nobahari \n" +"PO-Revision-Date: 2024-09-20 00:40+0000\n" +"Last-Translator: Danial Behzadi \n" "Language-Team: Persian \n" "Language: fa\n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "چشمانتان را آرام ببندید" # Short break msgid "Roll your eyes a few times to each side" @@ -114,6 +114,10 @@ msgstr "پروانه" msgid "List of Contributors" msgstr "لیست مشارکت‌کنندگان" +# About dialog +msgid "Help us translate this app" +msgstr "کمک به ترجمهٔ این کاره" + # Break screen msgid "Skip" msgstr "ردکن" @@ -577,7 +581,7 @@ msgid "Disable permanently" msgstr "غیرفعال کردن دائمی" msgid "License:" -msgstr "" +msgstr "پروانه:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/fr/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/fr/LC_MESSAGES/safeeyes.po index 66816dde..4cfc6cfb 100644 --- a/safeeyes/config/locale/fr/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/fr/LC_MESSAGES/safeeyes.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2022-01-11 15:55+0000\n" +"PO-Revision-Date: 2024-11-12 23:00+0000\n" "Last-Translator: AO Localisation Lab \n" "Language-Team: French \n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.10.1\n" +"X-Generator: Weblate 5.9-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Fermez doucement les yeux" # Short break msgid "Roll your eyes a few times to each side" @@ -113,7 +113,11 @@ msgstr "Licence" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Liste des contributeurs" + +# About dialog +msgid "Help us translate this app" +msgstr "Aidez-nous à traduire cette appli" # Break screen msgid "Skip" @@ -506,15 +510,15 @@ msgstr "Prendre une pause maintenant" #: plugins/trayicon msgid "Any break" -msgstr "" +msgstr "N’importe quelle pause" #: plugins/trayicon msgid "Short break" -msgstr "" +msgstr "Pause courte" #: plugins/trayicon msgid "Long break" -msgstr "" +msgstr "Pause longue" #: plugins/trayicon msgid "Until restart" @@ -522,7 +526,7 @@ msgstr "Jusqu’au redémarrage" #: plugins/trayicon msgid "Quit" -msgstr "Fermer" +msgstr "Quitter" # plugin/mediacontrol msgid "Media Control" @@ -538,57 +542,61 @@ msgstr "Mettre le contenu multimédia en pause" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "Limiter les sauts de pause consécutifs" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "Nombre de sauts ou de reports autorisés d’affilée" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "Limiter le nombre de pauses sautées ou reportées d’affilée" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "%(num)d/%(allowed)d pauses sautées ou reportées d’affilée" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "Prévention des lésions attribuables au travail répétitif" msgid "" "Please install service providing tray icons for your desktop environment." msgstr "" +"Installez le service qui fournit les icônes de la barre d’état pour votre " +"environnement de bureau." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "Prochaine pause longue à %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "Prochaines pauses à %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "Il manque des dépendances pour le greffon « %s » nécessaire" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"Installez les dépendances ou désactivez le greffon. Pour ne plus afficher ce " +"message, vous pouvez aussi désactiver le greffon dans les paramètres." msgid "Click here for more information" -msgstr "" +msgstr "Cliquer ici pour plus de précisions" msgid "Disable plugin temporarily" -msgstr "" +msgstr "Désactivation temporaire du greffon" msgid "Disable permanently" -msgstr "" +msgstr "Désactivation permanente" msgid "License:" -msgstr "" +msgstr "Licence :" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/he/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/he/LC_MESSAGES/safeeyes.po index f716ad1e..1634d09d 100644 --- a/safeeyes/config/locale/he/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/he/LC_MESSAGES/safeeyes.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-23 09:32+0000\n" +"PO-Revision-Date: 2024-11-11 13:00+0000\n" "Last-Translator: Yaron Shahrabani \n" "Language-Team: Hebrew \n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 5.8.2\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "לעצום את העיניים בעדינות" # Short break msgid "Roll your eyes a few times to each side" @@ -110,7 +110,11 @@ msgstr "רישיון" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "רשימת תורמים" + +# About dialog +msgid "Help us translate this app" +msgstr "נשמח לסיוע בתרגום היישום הזה" # Break screen msgid "Skip" @@ -491,15 +495,15 @@ msgstr "לקחת הפסקה עכשיו" #: plugins/trayicon msgid "Any break" -msgstr "" +msgstr "כל הפסקה שהיא" #: plugins/trayicon msgid "Short break" -msgstr "" +msgstr "הפסקה קצרה" #: plugins/trayicon msgid "Long break" -msgstr "" +msgstr "הפסקה ארוכה" #: plugins/trayicon msgid "Until restart" @@ -523,57 +527,59 @@ msgstr "השהיית מדיה" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "הגבלת דילוג מחזורי" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "כמה דילוגים או השהיות מותר ברצף" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "הגבלת כמות ההפסקות שאפשר לדלג או להשהות ברצף" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "דילגת או השהית %(num)d/%(allowed)d הפסקות ברצף" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "מניעת פציעת מאמץ חוזרני" msgid "" "Please install service providing tray icons for your desktop environment." -msgstr "" +msgstr "נא להתקין שירות שמספק סמלי שורת מערכת לסביבת שולחן העבודה שלך." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "ההפסקה הארוכה הבאה ב־%s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "ההפסקות הבאות ב־%(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "לתוסף ההכרחי ‚%s’ חסרות תלויות!" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"נא להתקין את התלויות או להשבית את התוסף. כדי להסתיר את ההודעה הזאת ניתן גם " +"להשבית את התוסף בהגדרות." msgid "Click here for more information" -msgstr "" +msgstr "לחיצה כאן תציג מידע נוסף" msgid "Disable plugin temporarily" -msgstr "" +msgstr "השבתת תוסף זמנית" msgid "Disable permanently" -msgstr "" +msgstr "השבתה לצמיתות" msgid "License:" -msgstr "" +msgstr "רישיון:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/hi/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/hi/LC_MESSAGES/safeeyes.po index cb6101a7..d2e4ecab 100644 --- a/safeeyes/config/locale/hi/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/hi/LC_MESSAGES/safeeyes.po @@ -110,6 +110,10 @@ msgstr "लाइसेंस" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "छोड़ें" diff --git a/safeeyes/config/locale/hu/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/hu/LC_MESSAGES/safeeyes.po index 6abb5c61..c7017ada 100644 --- a/safeeyes/config/locale/hu/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/hu/LC_MESSAGES/safeeyes.po @@ -110,6 +110,10 @@ msgstr "Licensz" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Kihagyás" diff --git a/safeeyes/config/locale/id/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/id/LC_MESSAGES/safeeyes.po index 54eda328..4d5db377 100644 --- a/safeeyes/config/locale/id/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/id/LC_MESSAGES/safeeyes.po @@ -112,6 +112,10 @@ msgstr "Lisensi" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Lewati" diff --git a/safeeyes/config/locale/it/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/it/LC_MESSAGES/safeeyes.po index 09584d2b..b8d830ab 100644 --- a/safeeyes/config/locale/it/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/it/LC_MESSAGES/safeeyes.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-07-02 12:09+0000\n" +"PO-Revision-Date: 2024-08-27 19:09+0000\n" "Last-Translator: albanobattistella \n" "Language-Team: Italian \n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.7.1-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Chiudi dolcemente gli occhi" # Short break msgid "Roll your eyes a few times to each side" @@ -114,6 +114,10 @@ msgstr "Licenza" msgid "List of Contributors" msgstr "Elenco dei contributori" +# About dialog +msgid "Help us translate this app" +msgstr "Aiutaci a tradurre questa app" + # Break screen msgid "Skip" msgstr "Salta" @@ -587,7 +591,7 @@ msgid "Disable permanently" msgstr "Disattivare in modo permanente" msgid "License:" -msgstr "" +msgstr "Licenza:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/kn/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/kn/LC_MESSAGES/safeeyes.po index e829bec9..407426d9 100644 --- a/safeeyes/config/locale/kn/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/kn/LC_MESSAGES/safeeyes.po @@ -112,6 +112,10 @@ msgstr "ಪರವಾನಿಗೆ" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "" diff --git a/safeeyes/config/locale/ko/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/ko/LC_MESSAGES/safeeyes.po index bbdc5af6..43b678bf 100644 --- a/safeeyes/config/locale/ko/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/ko/LC_MESSAGES/safeeyes.po @@ -112,6 +112,10 @@ msgstr "라이선스" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "넘기기" diff --git a/safeeyes/config/locale/lt/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/lt/LC_MESSAGES/safeeyes.po index c712d85d..6f826377 100644 --- a/safeeyes/config/locale/lt/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/lt/LC_MESSAGES/safeeyes.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-07-02 12:09+0000\n" +"PO-Revision-Date: 2024-10-14 06:16+0000\n" "Last-Translator: openSUSE Lietuviškai \n" "Language-Team: Lithuanian \n" @@ -14,13 +14,13 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"(n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.7-dev\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (" +"n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Švelniai užsimerkite" # Short break msgid "Roll your eyes a few times to each side" @@ -113,7 +113,11 @@ msgstr "Licencija" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Talkininkų sąrašas" + +# About dialog +msgid "Help us translate this app" +msgstr "Padėkite mums išversti šią programą" # Break screen msgid "Skip" @@ -533,57 +537,60 @@ msgstr "Pristabdyti mediją" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "Apriboti nuoseklų praleidinėjimą" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "Kiek leidžiama praleisti arba atidėti kartų iš eilės" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "Apriboti, kiek kartų galima iš eilės praleisti arba atidėti pertraukų" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "Paeiliui praleistos arba atidėtos pertraukos: %(num)d/%(allowed)d" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "Apsaugokite savo akis nuo įtampos" msgid "" "Please install service providing tray icons for your desktop environment." msgstr "" +"Prašome įdiegti savo darbalaukio aplinkos sistemos ženkliukų dėklo paslaugą." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "Kita ilga pertrauka: %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "Kitos pertraukos: %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "Reikalingam papildiniui „%s“ trūksta priklausomybių!" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"Prašome įdiegti priklausomybes arba pašalinti papildinį. Norėdami paslėpti " +"šį pranešimą, taip pat galite išjungti šį papildinį nuostatose." msgid "Click here for more information" -msgstr "" +msgstr "Norėdami sužinoti daugiau, spauskite čia" msgid "Disable plugin temporarily" -msgstr "" +msgstr "Laikinai išjungti papildinį" msgid "Disable permanently" -msgstr "" +msgstr "Išjungti visam laikui" msgid "License:" -msgstr "" +msgstr "Licencija:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/lv/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/lv/LC_MESSAGES/safeeyes.po index 28bcc6b1..149e29d7 100644 --- a/safeeyes/config/locale/lv/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/lv/LC_MESSAGES/safeeyes.po @@ -94,6 +94,10 @@ msgstr "Licence" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + msgid "Skip" msgstr "Izlaist" diff --git a/safeeyes/config/locale/mk/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/mk/LC_MESSAGES/safeeyes.po index 6c717b35..db3007e8 100644 --- a/safeeyes/config/locale/mk/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/mk/LC_MESSAGES/safeeyes.po @@ -112,6 +112,10 @@ msgstr "" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "" diff --git a/safeeyes/config/locale/mr/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/mr/LC_MESSAGES/safeeyes.po index 53406939..add11499 100644 --- a/safeeyes/config/locale/mr/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/mr/LC_MESSAGES/safeeyes.po @@ -111,6 +111,10 @@ msgstr "" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "" diff --git a/safeeyes/config/locale/nb/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/nb/LC_MESSAGES/safeeyes.po index 9dcde6ad..5d99e1e4 100644 --- a/safeeyes/config/locale/nb/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/nb/LC_MESSAGES/safeeyes.po @@ -113,6 +113,10 @@ msgstr "Lisens" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Hopp over" diff --git a/safeeyes/config/locale/nl/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/nl/LC_MESSAGES/safeeyes.po index a0dba578..790fc155 100644 --- a/safeeyes/config/locale/nl/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/nl/LC_MESSAGES/safeeyes.po @@ -115,6 +115,10 @@ msgstr "Licentie" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Overslaan" diff --git a/safeeyes/config/locale/pl/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/pl/LC_MESSAGES/safeeyes.po index 227bd122..18696bef 100644 --- a/safeeyes/config/locale/pl/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/pl/LC_MESSAGES/safeeyes.po @@ -115,6 +115,10 @@ msgstr "Licencja" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Pomiń" diff --git a/safeeyes/config/locale/pt/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/pt/LC_MESSAGES/safeeyes.po index 7a51a0e0..197a99ce 100644 --- a/safeeyes/config/locale/pt/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/pt/LC_MESSAGES/safeeyes.po @@ -115,6 +115,10 @@ msgstr "Licença" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Ignorar" diff --git a/safeeyes/config/locale/pt_BR/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/pt_BR/LC_MESSAGES/safeeyes.po index b8eedf57..e3f0d322 100644 --- a/safeeyes/config/locale/pt_BR/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/pt_BR/LC_MESSAGES/safeeyes.po @@ -114,6 +114,10 @@ msgstr "Licença" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Pular" diff --git a/safeeyes/config/locale/ru/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/ru/LC_MESSAGES/safeeyes.po index f8794c53..f0bd9a8b 100644 --- a/safeeyes/config/locale/ru/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/ru/LC_MESSAGES/safeeyes.po @@ -6,21 +6,21 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-11-26 00:02+0000\n" -"Last-Translator: Almaz Mannanov \n" +"PO-Revision-Date: 2024-09-06 22:09+0000\n" +"Last-Translator: AircGroup \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 5.2.1-rc\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Аккуратно закройте глаза" # Short break msgid "Roll your eyes a few times to each side" @@ -113,7 +113,11 @@ msgstr "Лицензия" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Список участников проекта" + +# About dialog +msgid "Help us translate this app" +msgstr "Помоги нам перевести приложение" # Break screen msgid "Skip" @@ -500,15 +504,15 @@ msgstr "Отдохнуть сейчас" #: plugins/trayicon msgid "Any break" -msgstr "" +msgstr "Сделайте перерыв на что угодно" #: plugins/trayicon msgid "Short break" -msgstr "" +msgstr "Небольшой перерыв" #: plugins/trayicon msgid "Long break" -msgstr "" +msgstr "Долгий перерыв" #: plugins/trayicon msgid "Until restart" @@ -532,57 +536,61 @@ msgstr "Приостановить воспроизведение" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "Ограничение пропусков подряд" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "Сколько пропусков или переносов разрешено подряд" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "Какое количество перерывов можно пропустить или отложить подряд" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "Пропущенные или отложенные %(num)d/%(allowed)d перерывы подряд" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "Профилактика RSI" msgid "" "Please install service providing tray icons for your desktop environment." msgstr "" +"Пожалуйста, установите ПО предоставляющий иконки в трее для вашего рабочего " +"стола." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "Следующий длительный перерыв в %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "Следующие перерывы %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "В требуемом плагине '%s' отсутствуют зависимости!" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"Пожалуйста, установите зависимости или отключите плагин. Чтобы скрыть это " +"сообщение, вы также можете отключить плагин в настройках." msgid "Click here for more information" -msgstr "" +msgstr "Нажмите здесь для получения дополнительной информации" msgid "Disable plugin temporarily" -msgstr "" +msgstr "Временно отключите плагин" msgid "Disable permanently" -msgstr "" +msgstr "Отключить навсегда" msgid "License:" -msgstr "" +msgstr "Лицензия:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/safeeyes.pot b/safeeyes/config/locale/safeeyes.pot index 521c894e..d9fe78c7 100644 --- a/safeeyes/config/locale/safeeyes.pot +++ b/safeeyes/config/locale/safeeyes.pot @@ -94,6 +94,10 @@ msgstr "" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "" diff --git a/safeeyes/config/locale/sk/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/sk/LC_MESSAGES/safeeyes.po index d0e7a3c1..62b479b9 100644 --- a/safeeyes/config/locale/sk/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/sk/LC_MESSAGES/safeeyes.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-07-10 11:09+0000\n" -"Last-Translator: menom \n" +"PO-Revision-Date: 2024-11-02 20:00+0000\n" +"Last-Translator: Milan Šalka \n" "Language-Team: Slovak \n" "Language: sk\n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8.2\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Jemne zavrite oči" # Short break msgid "Roll your eyes a few times to each side" @@ -113,7 +113,11 @@ msgstr "Licencia" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Zoznam Prispievateľov" + +# About dialog +msgid "Help us translate this app" +msgstr "Pomôžte nám preložiť túto aplikáciu" # Break screen msgid "Skip" @@ -529,57 +533,61 @@ msgstr "Pozastaviť média" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "Limit Konzekutívne lyžovanie" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "Koľko preskokov alebo odložiek je povolené v rade" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" -msgstr "" +msgstr "Limit, koľko prestávky je možné preskočiť alebo odložiť v rade" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "Sklo alebo odložené %(num)d/%(allowed)d prestávky v rade" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "Prevencia RSI" msgid "" "Please install service providing tray icons for your desktop environment." msgstr "" +"Prosím, nainštalujte službu poskytujúce zásobníkové ikony pre vaše " +"desktopové prostredie." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "Najdlhšia prestávka na %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "Ďalšie prestávky na %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "Požadovaný plugin '%s chýba závislosti!" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"Prosím, nainštalujte záhady alebo vypnúť plugin. Ak chcete skryť túto " +"správu, môžete tiež deaktivovať plugin v nastavení." msgid "Click here for more information" -msgstr "" +msgstr "Kliknite tu pre viac informácií" msgid "Disable plugin temporarily" -msgstr "" +msgstr "Disable plugin dočasne" msgid "Disable permanently" -msgstr "" +msgstr "Zakázať trvalo" msgid "License:" -msgstr "" +msgstr "Licencia:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/sr/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/sr/LC_MESSAGES/safeeyes.po index d714f8ec..154538ec 100644 --- a/safeeyes/config/locale/sr/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/sr/LC_MESSAGES/safeeyes.po @@ -115,6 +115,10 @@ msgstr "Лиценца" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Прескочите" diff --git a/safeeyes/config/locale/sv/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/sv/LC_MESSAGES/safeeyes.po index eccb600e..d004baee 100644 --- a/safeeyes/config/locale/sv/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/sv/LC_MESSAGES/safeeyes.po @@ -112,6 +112,10 @@ msgstr "Licens" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Hoppa över" diff --git a/safeeyes/config/locale/ta/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/ta/LC_MESSAGES/safeeyes.po index 0ed204b1..db7db2e9 100644 --- a/safeeyes/config/locale/ta/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/ta/LC_MESSAGES/safeeyes.po @@ -115,6 +115,10 @@ msgstr "மென்பொருள் உரிமம்" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "தவிர்" diff --git a/safeeyes/config/locale/tr/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/tr/LC_MESSAGES/safeeyes.po index 355de906..830a3af3 100644 --- a/safeeyes/config/locale/tr/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/tr/LC_MESSAGES/safeeyes.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2024-06-28 17:09+0000\n" +"PO-Revision-Date: 2024-09-02 07:09+0000\n" "Last-Translator: Oğuz Ersen \n" "Language-Team: Turkish \n" @@ -15,11 +15,11 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8-dev\n" # Short break msgid "Gently close your eyes" -msgstr "" +msgstr "Yavaşça gözlerinizi kapatın" # Short break msgid "Roll your eyes a few times to each side" @@ -113,7 +113,11 @@ msgstr "Lisans" # About dialog msgid "List of Contributors" -msgstr "" +msgstr "Katkıda Bulunanların Listesi" + +# About dialog +msgid "Help us translate this app" +msgstr "Bu uygulamayı çevirmemize yardım edin" # Break screen msgid "Skip" @@ -529,57 +533,60 @@ msgstr "Ortamı duraklat" # plugin/limitconsecutiveskipping msgid "Limit Consecutive Skipping" -msgstr "" +msgstr "Ardışık Geçmeyi Sınırla" # plugin/limitconsecutiveskipping msgid "How many skips or postpones are allowed in a row" -msgstr "" +msgstr "Arka arkaya kaç geçmeye veya ertelemeye izin verilir" # plugin/limitconsecutiveskipping msgid "Limit how many breaks can be skipped or postponed in a row" msgstr "" +"Arka arkaya kaç molanın geçilebileceğini veya ertelenebileceğini sınırlayın" # plugin/limitconsecutiveskipping #, python-format msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row" -msgstr "" +msgstr "Arka arkaya %(num)d/%(allowed)d mola geçildi veya ertelendi" # safeeyes/platform/io.github.slgobinath.SafeEyes.desktop msgid "RSI Prevention" -msgstr "" +msgstr "Tekrarlayan zorlanma yaralanmalarının önlenmesi" msgid "" "Please install service providing tray icons for your desktop environment." -msgstr "" +msgstr "Lütfen masaüstü ortamınız için tepsi simgeleri sağlayan hizmeti kurun." #, python-format msgid "Next long break at %s" -msgstr "" +msgstr "Sonraki uzun mola: %s" #, python-format msgid "Next breaks at %(short)s/%(long)s" -msgstr "" +msgstr "Sonraki mola: %(short)s/%(long)s" #, python-format msgid "The required plugin '%s' is missing dependencies!" -msgstr "" +msgstr "Gerekli '%s' eklentisinin bağımlılıkları eksik!" msgid "" "Please install the dependencies or disable the plugin. To hide this message, " "you can also deactivate the plugin in the settings." msgstr "" +"Lütfen bağımlılıkları kurun veya eklentiyi devre dışı bırakın. Bu mesajı " +"gizlemek için eklentiyi ayarlardan da devre dışı bırakabilirsiniz." msgid "Click here for more information" -msgstr "" +msgstr "Daha fazla bilgi için buraya tıklayın" msgid "Disable plugin temporarily" -msgstr "" +msgstr "Eklentiyi geçici olarak devre dışı bırak" msgid "Disable permanently" -msgstr "" +msgstr "Kalıcı olarak devre dışı bırak" msgid "License:" -msgstr "" +msgstr "Lisans:" # Short break #~ msgid "Tightly close your eyes" diff --git a/safeeyes/config/locale/ug/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/ug/LC_MESSAGES/safeeyes.po index a7e1b78a..5fe2594a 100644 --- a/safeeyes/config/locale/ug/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/ug/LC_MESSAGES/safeeyes.po @@ -109,6 +109,10 @@ msgstr "" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "" diff --git a/safeeyes/config/locale/uk/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/uk/LC_MESSAGES/safeeyes.po index f71e5753..acaf54e3 100644 --- a/safeeyes/config/locale/uk/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/uk/LC_MESSAGES/safeeyes.po @@ -113,6 +113,10 @@ msgstr "Ліцензія" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Пропустити" diff --git a/safeeyes/config/locale/uz_Latn/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/uz_Latn/LC_MESSAGES/safeeyes.po index 89a7395b..bd4aab85 100644 --- a/safeeyes/config/locale/uz_Latn/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/uz_Latn/LC_MESSAGES/safeeyes.po @@ -109,6 +109,10 @@ msgstr "" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "" diff --git a/safeeyes/config/locale/vi/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/vi/LC_MESSAGES/safeeyes.po index e0dc5528..23827c8f 100644 --- a/safeeyes/config/locale/vi/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/vi/LC_MESSAGES/safeeyes.po @@ -114,6 +114,10 @@ msgstr "Giấy phép" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "Bỏ qua" diff --git a/safeeyes/config/locale/zh_CN/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/zh_CN/LC_MESSAGES/safeeyes.po index b427cb7c..fc25b4b3 100644 --- a/safeeyes/config/locale/zh_CN/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/zh_CN/LC_MESSAGES/safeeyes.po @@ -113,6 +113,10 @@ msgstr "许可" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "跳过" diff --git a/safeeyes/config/locale/zh_TW/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/zh_TW/LC_MESSAGES/safeeyes.po index ab233af5..11d8252c 100644 --- a/safeeyes/config/locale/zh_TW/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/zh_TW/LC_MESSAGES/safeeyes.po @@ -110,6 +110,10 @@ msgstr "授權" msgid "List of Contributors" msgstr "" +# About dialog +msgid "Help us translate this app" +msgstr "" + # Break screen msgid "Skip" msgstr "跳過" diff --git a/safeeyes/glade/about_dialog.glade b/safeeyes/glade/about_dialog.glade index 8ee6875b..fc6ab89f 100644 --- a/safeeyes/glade/about_dialog.glade +++ b/safeeyes/glade/about_dialog.glade @@ -71,7 +71,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.center 10 10 - Safe Eyes 2.2.2 + Safe Eyes 2.2.3 center @@ -207,6 +207,23 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.1 + + + Help us translate this app + True + True + False + True + center + none + https://github.com/slgobinath/SafeEyes?tab=readme-ov-file#how-you-can-help-improving-translation-of-safe-eyes + + + False + True + 2 + + False diff --git a/safeeyes/model.py b/safeeyes/model.py index e57a1f79..888a6bc1 100644 --- a/safeeyes/model.py +++ b/safeeyes/model.py @@ -24,6 +24,7 @@ import random from enum import Enum from dataclasses import dataclass +from typing import Optional, Union from packaging.version import parse @@ -424,10 +425,11 @@ def build(cls, name, icon_path, icon_id, action): @dataclass class PluginDependency: message: str - link: str|None = None + link: Optional[str] = None + retryable: bool = False class RequiredPluginException(Exception): - def __init__(self, plugin_id, plugin_name: str, message: str|PluginDependency): + def __init__(self, plugin_id, plugin_name: str, message: Union[str, PluginDependency]): if isinstance(message, PluginDependency): msg = message.message else: diff --git a/safeeyes/platform/io.github.slgobinath.SafeEyes.metainfo.xml b/safeeyes/platform/io.github.slgobinath.SafeEyes.metainfo.xml index ad599ffc..408001c9 100644 --- a/safeeyes/platform/io.github.slgobinath.SafeEyes.metainfo.xml +++ b/safeeyes/platform/io.github.slgobinath.SafeEyes.metainfo.xml @@ -53,6 +53,7 @@ https://slgobinath.github.io/SafeEyes/ + diff --git a/safeeyes/plugin_manager.py b/safeeyes/plugin_manager.py index 1bc3f8f6..41ea4130 100644 --- a/safeeyes/plugin_manager.py +++ b/safeeyes/plugin_manager.py @@ -57,14 +57,13 @@ import sys from safeeyes import utility -from safeeyes.model import RequiredPluginException +from safeeyes.model import PluginDependency, RequiredPluginException sys.path.append(os.path.abspath(utility.SYSTEM_PLUGINS_DIR)) sys.path.append(os.path.abspath(utility.USER_PLUGINS_DIR)) HORIZONTAL_LINE_LENGTH = 64 - class PluginManager: """ Imports the Safe Eyes plugins and calls the methods defined in those plugins. @@ -73,17 +72,6 @@ class PluginManager: def __init__(self): logging.info('Load all the plugins') self.__plugins = {} - self.__plugins_on_init = [] - self.__plugins_on_start = [] - self.__plugins_on_stop = [] - self.__plugins_on_exit = [] - self.__plugins_on_pre_break = [] - self.__plugins_on_start_break = [] - self.__plugins_on_stop_break = [] - self.__plugins_on_countdown = [] - self.__plugins_update_next_break = [] - self.__widget_plugins = [] - self.__tray_actions_plugins = [] self.last_break = None self.horizontal_line = '─' * HORIZONTAL_LINE_LENGTH @@ -94,7 +82,8 @@ def init(self, context, config): # Load the plugins for plugin in config.get('plugins'): try: - self.__load_plugin(plugin) + loaded_plugin = LoadedPlugin(plugin) + self.__plugins[loaded_plugin.id] = loaded_plugin except RequiredPluginException as e: raise e except BaseException as e: @@ -105,42 +94,62 @@ def init(self, context, config): logging.error('Error in loading the plugin %s: %s', plugin['id'], e) continue # Initialize the plugins - for plugin in self.__plugins_on_init: - plugin['module'].init(context, config, plugin['config']) + for plugin in self.__plugins.values(): + plugin.init_plugin(context, config) return True + def needs_retry(self): + return self.get_retryable_error() is not None + + def get_retryable_error(self): + for plugin in self.__plugins.values(): + if plugin.required_plugin and plugin.errored and plugin.enabled: + if isinstance(plugin.last_error, PluginDependency) and plugin.last_error.retryable: + return RequiredPluginException( + plugin.id, + plugin.get_name(), + plugin.last_error + ) + + return None + + def retry_errored_plugins(self): + for plugin in self.__plugins.values(): + if plugin.required_plugin and plugin.errored and plugin.enabled: + if isinstance(plugin.last_error, PluginDependency) and plugin.last_error.retryable: + plugin.reload_errored() + def start(self): """ Execute the on_start() function of plugins. """ - for plugin in self.__plugins_on_start: - plugin['module'].on_start() + for plugin in self.__plugins.values(): + plugin.call_plugin_method("on_start") return True def stop(self): """ Execute the on_stop() function of plugins. """ - for plugin in self.__plugins_on_stop: - plugin['module'].on_stop() + for plugin in self.__plugins.values(): + plugin.call_plugin_method("on_stop") return True def exit(self): """ Execute the on_exit() function of plugins. """ - for plugin in self.__plugins_on_exit: - plugin['module'].on_exit() + for plugin in self.__plugins.values(): + plugin.call_plugin_method("on_exit") return True def pre_break(self, break_obj): """ Execute the on_pre_break(break_obj) function of plugins. """ - for plugin in self.__plugins_on_pre_break: - if break_obj.plugin_enabled(plugin['id'], plugin['enabled']): - if plugin['module'].on_pre_break(break_obj): - return False + for plugin in self.__plugins.values(): + if plugin.call_plugin_method_break_obj("on_pre_break", 1, break_obj): + return False return True def start_break(self, break_obj): @@ -148,10 +157,9 @@ def start_break(self, break_obj): Execute the start_break(break_obj) function of plugins. """ self.last_break = break_obj - for plugin in self.__plugins_on_start_break: - if break_obj.plugin_enabled(plugin['id'], plugin['enabled']): - if plugin['module'].on_start_break(break_obj): - return False + for plugin in self.__plugins.values(): + if plugin.call_plugin_method_break_obj("on_start_break", 1, break_obj): + return False return True @@ -159,24 +167,22 @@ def stop_break(self): """ Execute the stop_break() function of plugins. """ - for plugin in self.__plugins_on_stop_break: - if self.last_break.plugin_enabled(plugin['id'], plugin['enabled']): - plugin['module'].on_stop_break() + for plugin in self.__plugins.values(): + plugin.call_plugin_method("on_stop_break") def countdown(self, countdown, seconds): """ Execute the on_countdown(countdown, seconds) function of plugins. """ - for plugin in self.__plugins_on_countdown: - if self.last_break.plugin_enabled(plugin['id'], plugin['enabled']): - plugin['module'].on_countdown(countdown, seconds) + for plugin in self.__plugins.values(): + plugin.call_plugin_method("on_countdown", 2, countdown, seconds) def update_next_break(self, break_obj, break_time): """ Execute the update_next_break(break_time) function of plugins. """ - for plugin in self.__plugins_update_next_break: - plugin['module'].update_next_break(break_obj, break_time) + for plugin in self.__plugins.values(): + plugin.call_plugin_method_break_obj("update_next_break", 2, break_obj, break_time) return True def get_break_screen_widgets(self, break_obj): @@ -185,18 +191,20 @@ def get_break_screen_widgets(self, break_obj): The widget is generated by calling the get_widget_title and get_widget_content functions of plugins. """ widget = '' - for plugin in self.__widget_plugins: - if break_obj.plugin_enabled(plugin['id'], plugin['enabled']): - try: - title = plugin['module'].get_widget_title(break_obj).upper().strip() - if title == '': - continue - content = plugin['module'].get_widget_content(break_obj) - if content == '': - continue - widget += '{}\n{}\n{}\n\n\n'.format(title, self.horizontal_line, content) - except BaseException: + for plugin in self.__plugins.values(): + try: + title = plugin.call_plugin_method_break_obj("get_widget_title", 1, break_obj) + if title is None or not isinstance(title, str) or title == '': + continue + content = plugin.call_plugin_method_break_obj("get_widget_content", 1, break_obj) + if content is None or not isinstance(content, str) or content == '': + continue + title = title.upper().strip() + if title == '': continue + widget += '{}\n{}\n{}\n\n\n'.format(title, self.horizontal_line, content) + except BaseException: + continue return widget.strip() def get_break_screen_tray_actions(self, break_obj): @@ -204,151 +212,186 @@ def get_break_screen_tray_actions(self, break_obj): Return Tray Actions. """ actions = [] - for plugin in self.__tray_actions_plugins: - if break_obj.plugin_enabled(plugin['id'], plugin['enabled']): - action = plugin['module'].get_tray_action(break_obj) - if action: - actions.append(action) + for plugin in self.__plugins.values(): + action = plugin.call_plugin_method_break_obj("get_tray_action", 1, break_obj) + if action: + actions.append(action) return actions - def __load_plugin(self, plugin): - """ - Load the given plugin. - """ - plugin_enabled = plugin['enabled'] - if plugin['id'] in self.__plugins and not plugin_enabled: - # A disabled plugin but that was loaded earlier - plugin_obj = self.__plugins[plugin['id']] - if plugin_obj['enabled']: - # Previously enabled but now disabled - plugin_obj['enabled'] = False - utility.remove_if_exists(self.__plugins_on_start, plugin_obj) - utility.remove_if_exists(self.__plugins_on_stop, plugin_obj) - utility.remove_if_exists(self.__plugins_on_exit, plugin_obj) - utility.remove_if_exists(self.__plugins_update_next_break, plugin_obj) - # Call the plugin.disable method if available - if utility.has_method(plugin_obj['module'], 'disable'): - plugin_obj['module'].disable() - logging.info("Successfully unloaded the plugin '%s'", plugin['id']) - - if not plugin_obj['break_override_allowed']: - # Remaining methods also should be removed - utility.remove_if_exists(self.__plugins_on_init, plugin_obj) - utility.remove_if_exists(self.__plugins_on_pre_break, plugin_obj) - utility.remove_if_exists(self.__plugins_on_start_break, plugin_obj) - utility.remove_if_exists(self.__plugins_on_stop_break, plugin_obj) - utility.remove_if_exists(self.__plugins_on_countdown, plugin_obj) - utility.remove_if_exists(self.__widget_plugins, plugin_obj) - utility.remove_if_exists(self.__tray_actions_plugins, plugin_obj) - del self.__plugins[plugin['id']] + +class LoadedPlugin: + # state of the plugin + enabled: bool = False + break_override_allowed: bool = False + errored: bool = False + required_plugin: bool = False + + # misc data + # FIXME: rename to plugin_config to plugin_json? plugin_config and config are easy to confuse + config = None + plugin_config = None + plugin_dir = None + module = None + last_error = None + id = None + + def __init__(self, plugin): + (plugin_config, plugin_dir) = self._load_config_json(plugin['id']) + + self.id = plugin['id'] + self.plugin_config = plugin_config + self.plugin_dir = plugin_dir + self.enabled = plugin["enabled"] + self.break_override_allowed = plugin_config.get('break_override_allowed', False) + self.required_plugin = plugin_config.get("required_plugin", False) + + self.config = dict(plugin.get('settings', {})) + self.config['path'] = os.path.join(plugin_dir, plugin['id']) + + if self.enabled or self.break_override_allowed: + plugin_path = os.path.join(plugin_dir, self.id) + message = utility.check_plugin_dependencies(plugin['id'], plugin_config, plugin.get('settings', {}), plugin_path) + + if message: + self.errored = True + self.last_error = message + if self.required_plugin and not (isinstance(message, PluginDependency) and message.retryable): + raise RequiredPluginException( + plugin['id'], + plugin_config['meta']['name'], + message + ) + return + + self._import_plugin() + + + def reload_config(self, plugin): + if self.enabled and not plugin["enabled"]: + self.enabled = False + if not self.errored and utility.has_method(self.module, 'disable'): + self.module.disable() + + if not self.enabled and plugin["enabled"]: + self.enabled = True + + # Update the config + self.config = dict(plugin.get('settings', {})) + self.config['path'] = os.path.join(self.plugin_dir, plugin['id']) + + if self.enabled or self.break_override_allowed: + plugin_path = os.path.join(self.plugin_dir, self.id) + message = utility.check_plugin_dependencies( + self.id, + self.plugin_config, + self.config, + plugin_path + ) + + if message: + self.errored = True + self.last_error = message + elif self.errored: + self.errored = False + self.last_error = None + + if not self.errored and self.module is None: + # No longer errored, import the module now + self._import_plugin() + + + def reload_errored(self): + if not self.errored: return + if self.enabled or self.break_override_allowed: + plugin_path = os.path.join(self.plugin_dir, self.id) + message = utility.check_plugin_dependencies( + self.id, + self.plugin_config, + self.config, + plugin_path + ) + + if message: + self.errored = True + self.last_error = message + elif self.errored: + self.errored = False + self.last_error = None + + if not self.errored and self.module is None: + # No longer errored, import the module now + self._import_plugin() + + + def get_name(self): + return self.plugin_config['meta']['name'] + + def _import_plugin(self): + if self.errored: + # do not try to import errored plugin + return + + self.module = importlib.import_module((self.id + '.plugin')) + logging.info("Successfully loaded %s", str(self.module)) + + if utility.has_method(self.module, 'enable'): + self.module.enable() + + def _load_config_json(self, plugin_id): # Look for plugin.py - if os.path.isfile(os.path.join(utility.SYSTEM_PLUGINS_DIR, plugin['id'], 'plugin.py')): + if os.path.isfile(os.path.join(utility.SYSTEM_PLUGINS_DIR, plugin_id, 'plugin.py')): plugin_dir = utility.SYSTEM_PLUGINS_DIR - elif os.path.isfile(os.path.join(utility.USER_PLUGINS_DIR, plugin['id'], 'plugin.py')): + elif os.path.isfile(os.path.join(utility.USER_PLUGINS_DIR, plugin_id, 'plugin.py')): plugin_dir = utility.USER_PLUGINS_DIR else: - logging.error('plugin.py not found for the plugin: %s', plugin['id']) - return + raise Exception('plugin.py not found for the plugin: %s', plugin_id) # Look for config.json - plugin_path = os.path.join(plugin_dir, plugin['id']) + plugin_path = os.path.join(plugin_dir, plugin_id) plugin_config_path = os.path.join(plugin_path, 'config.json') if not os.path.isfile(plugin_config_path): - logging.error('config.json not found for the plugin: %s', plugin['id']) - return + raise Exception('config.json not found for the plugin: %s', plugin_id) plugin_config = utility.load_json(plugin_config_path) if plugin_config is None: + raise Exception('config.json empty/invalid for the plugin: %s', plugin_id) + + return (plugin_config, plugin_dir) + + def init_plugin(self, context, safeeyes_config): + if self.errored: return + if self.break_override_allowed or self.enabled: + if utility.has_method(self.module, 'init', 3): + self.module.init(context, safeeyes_config, self.config) - if plugin_enabled or plugin_config.get('break_override_allowed', False): - if plugin['id'] in self.__plugins: - # The plugin is already enabled or partially loaded due to break_override_allowed - - # Validate the dependencies again - if utility.check_plugin_dependencies(plugin['id'], plugin_config, plugin.get('settings', {}), plugin_path): - plugin_obj['enabled'] = False - utility.remove_if_exists(self.__plugins_on_start, plugin_obj) - utility.remove_if_exists(self.__plugins_on_stop, plugin_obj) - utility.remove_if_exists(self.__plugins_on_exit, plugin_obj) - utility.remove_if_exists(self.__plugins_update_next_break, plugin_obj) - utility.remove_if_exists(self.__plugins_on_init, plugin_obj) - utility.remove_if_exists(self.__plugins_on_pre_break, plugin_obj) - utility.remove_if_exists(self.__plugins_on_start_break, plugin_obj) - utility.remove_if_exists(self.__plugins_on_stop_break, plugin_obj) - utility.remove_if_exists(self.__plugins_on_countdown, plugin_obj) - utility.remove_if_exists(self.__widget_plugins, plugin_obj) - utility.remove_if_exists(self.__tray_actions_plugins, plugin_obj) - del self.__plugins[plugin['id']] - - # Use the existing plugin object - plugin_obj = self.__plugins[plugin['id']] - - # Update the config - plugin_obj['config'] = dict(plugin.get('settings', {})) - plugin_obj['config']['path'] = os.path.join(plugin_dir, plugin['id']) - - if plugin_obj['enabled']: - # Already loaded completely - return - # Plugin was partially loaded due to break_override_allowed - if plugin_enabled: - # Load the rest of the methods - plugin_obj['enabled'] = True - module = plugin_obj['module'] - self.__init_plugin(module, plugin_obj) - else: - # This is the first time to load the plugin - # Check for dependencies - message = utility.check_plugin_dependencies(plugin['id'], plugin_config, plugin.get('settings', {}), plugin_path) - if message: - if plugin_config.get('required_plugin', False): - raise RequiredPluginException( - plugin['id'], - plugin_config['meta']['name'], - message - ) - return - - # Load the plugin module - module = importlib.import_module((plugin['id'] + '.plugin')) - logging.info("Successfully loaded %s", str(module)) - plugin_obj = {'id': plugin['id'], 'module': module, 'config': dict(plugin.get( - 'settings', {})), 'enabled': plugin_enabled, - 'break_override_allowed': plugin_config.get('break_override_allowed', False)} - # Inject the plugin directory into the config - plugin_obj['config']['path'] = os.path.join(plugin_dir, plugin['id']) - self.__plugins[plugin['id']] = plugin_obj - if utility.has_method(module, 'enable'): - module.enable() - if plugin_enabled: - self.__init_plugin(module, plugin_obj) - if utility.has_method(module, 'init', 3): - self.__plugins_on_init.append(plugin_obj) - if utility.has_method(module, 'on_pre_break', 1): - self.__plugins_on_pre_break.append(plugin_obj) - if utility.has_method(module, 'on_start_break', 1): - self.__plugins_on_start_break.append(plugin_obj) - if utility.has_method(module, 'on_stop_break', 0): - self.__plugins_on_stop_break.append(plugin_obj) - if utility.has_method(module, 'on_countdown', 2): - self.__plugins_on_countdown.append(plugin_obj) - if utility.has_method(module, 'get_widget_title', 1) and utility.has_method(module, - 'get_widget_content', 1): - self.__widget_plugins.append(plugin_obj) - if utility.has_method(module, 'get_tray_action', 1): - self.__tray_actions_plugins.append(plugin_obj) - - def __init_plugin(self, module, plugin_obj): - """ - Collect mandatory methods from the plugin and add them to the life cycle methods list. - """ - if utility.has_method(module, 'on_start'): - self.__plugins_on_start.append(plugin_obj) - if utility.has_method(module, 'on_stop'): - self.__plugins_on_stop.append(plugin_obj) - if utility.has_method(module, 'on_exit'): - self.__plugins_on_exit.append(plugin_obj) - if utility.has_method(module, 'update_next_break', 2): - self.__plugins_update_next_break.append(plugin_obj) + def call_plugin_method_break_obj(self, method_name: str, num_args, break_obj, *args, **kwargs): + if self.errored: + return None + + enabled = False + if self.break_override_allowed: + enabled = break_obj.plugin_enabled(self.id, self.enabled) + else: + enabled = self.enabled + + if enabled: + return self._call_plugin_method_internal(method_name, num_args, break_obj, *args, **kwargs) + + return None + + def call_plugin_method(self, method_name: str, num_args=0, *args, **kwargs): + if self.errored: + return None + + if self.enabled: + return self._call_plugin_method_internal(method_name, num_args, *args, **kwargs) + + return None + + def _call_plugin_method_internal(self, method_name: str, num_args=0, *args, **kwargs): + # FIXME: cache if method exists + if utility.has_method(self.module, method_name, num_args): + return getattr(self.module, method_name)(*args, **kwargs) + return None diff --git a/safeeyes/plugins/healthstats/plugin.py b/safeeyes/plugins/healthstats/plugin.py index 126c1c86..5f97afe1 100644 --- a/safeeyes/plugins/healthstats/plugin.py +++ b/safeeyes/plugins/healthstats/plugin.py @@ -55,7 +55,8 @@ def init(ctx, safeeyes_config, plugin_config): 'total_resets': 0, } - session = context['session']['plugin'].get('healthstats', {}) | defaults + session = context['session']['plugin'].get('healthstats', {}).copy() + session.update(defaults) if 'no_of_breaks' in session: # Ignore old format session. session = defaults diff --git a/safeeyes/plugins/trayicon/dependency_checker.py b/safeeyes/plugins/trayicon/dependency_checker.py index d7a92f97..574433ad 100644 --- a/safeeyes/plugins/trayicon/dependency_checker.py +++ b/safeeyes/plugins/trayicon/dependency_checker.py @@ -39,7 +39,8 @@ def validate(plugin_config, plugin_settings): else: return PluginDependency( message=_("Please install service providing tray icons for your desktop environment."), - link="https://github.com/slgobinath/SafeEyes/wiki/How-to-install-backend-for-Safe-Eyes-tray-icon" + link="https://github.com/slgobinath/SafeEyes/wiki/How-to-install-backend-for-Safe-Eyes-tray-icon", + retryable=True ) command = None diff --git a/safeeyes/plugins/trayicon/plugin.py b/safeeyes/plugins/trayicon/plugin.py index 39766c18..42b309a5 100644 --- a/safeeyes/plugins/trayicon/plugin.py +++ b/safeeyes/plugins/trayicon/plugin.py @@ -49,6 +49,12 @@ + + + + + + """).interfaces[0] @@ -346,6 +352,7 @@ class StatusNotifierItemService(DBusService): IconName = 'io.github.slgobinath.SafeEyes-enabled' IconThemePath = '' ToolTip = ('', [], 'Safe Eyes', '') + XAyatanaLabel = "" ItemIsMenu = True Menu = None @@ -398,6 +405,14 @@ def set_tooltip(self, title, description): 'NewTooltip' ) + def set_xayatanalabel(self, label): + self.XAyatanaLabel = label + + self.emit_signal( + "XAyatanaNewLabel", + (label, "") + ) + class TrayIcon: """ Create and show the tray icon along with the tray menu. @@ -514,7 +529,7 @@ def get_items(self): disable_items.append({ 'id': disable_option_dynamic_id, 'label': label, - 'callback': lambda: self.on_disable_clicked(time_in_minutes), + 'callback': lambda time_in_minutes=time_in_minutes: self.on_disable_clicked(time_in_minutes), }) disable_option_dynamic_id += 1 @@ -611,6 +626,7 @@ def update_tooltip(self): description = '' self.sni_service.set_tooltip('Safe Eyes', description) + self.sni_service.set_xayatanalabel(description) def quit_safe_eyes(self): """ diff --git a/safeeyes/safeeyes.py b/safeeyes/safeeyes.py index 3188ec0b..bf94c9cc 100644 --- a/safeeyes/safeeyes.py +++ b/safeeyes/safeeyes.py @@ -37,9 +37,9 @@ from safeeyes.ui.settings_dialog import SettingsDialog gi.require_version('Gtk', '3.0') -from gi.repository import Gtk, Gio +from gi.repository import Gtk, Gio, GLib -SAFE_EYES_VERSION = "2.2.2" +SAFE_EYES_VERSION = "2.2.3" class SafeEyes(Gtk.Application): @@ -48,6 +48,7 @@ class SafeEyes(Gtk.Application): """ required_plugin_dialog_active = False + retry_errored_plugins_count = 0 def __init__(self, system_locale, config, cli_args): super().__init__( @@ -119,8 +120,7 @@ def do_startup(self): try: self.plugins_manager.init(self.context, self.config) except RequiredPluginException as e: - self.show_required_plugin_dialog(e.get_plugin_id(), e.get_plugin_name(), e.get_message()) - self.required_plugin_dialog_active = True + self.show_required_plugin_dialog(e) self.hold() @@ -129,7 +129,7 @@ def do_startup(self): if self.config.get('use_rpc_server', True): self.__start_rpc_server() - if not self.required_plugin_dialog_active and self.safe_eyes_core.has_breaks(): + if not self.plugins_manager.needs_retry() and not self.required_plugin_dialog_active and self.safe_eyes_core.has_breaks(): self.active = True self.context['state'] = State.START self.plugins_manager.start() # Call the start method of all plugins @@ -139,6 +139,9 @@ def do_startup(self): def do_activate(self): logging.info('Application activated') + if self.plugins_manager.needs_retry(): + GLib.timeout_add_seconds(1, self._retry_errored_plugins) + if self.cli_args.about: self.show_about() elif self.cli_args.disable: @@ -150,6 +153,32 @@ def do_activate(self): elif self.cli_args.take_break: self.take_break() + + def _retry_errored_plugins(self): + if not self.plugins_manager.needs_retry(): + return + + logging.info(f"Retry loading errored plugin") + self.plugins_manager.retry_errored_plugins() + + error = self.plugins_manager.get_retryable_error() + + if error is None: + # success + self.restart(self.config, set_active=True) + return + + # errored again + if self.retry_errored_plugins_count >= 3: + self.show_required_plugin_dialog(error) + return + + timeout = pow(2, self.retry_errored_plugins_count) + self.retry_errored_plugins_count += 1 + + GLib.timeout_add_seconds(timeout, self._retry_errored_plugins) + + def show_settings(self): """ Listen to tray icon Settings action and send the signal to Settings dialog. @@ -161,12 +190,14 @@ def show_settings(self): self.config.clone(), self.save_settings) settings_dialog.show() - def show_required_plugin_dialog(self, plugin_id, plugin_name, message): + def show_required_plugin_dialog(self, error: RequiredPluginException): + self.required_plugin_dialog_active = True + logging.info("Show RequiredPlugin dialog") dialog = RequiredPluginDialog( - plugin_id, - plugin_name, - message, + error.get_plugin_id(), + error.get_plugin_name(), + error.get_message(), self.quit, lambda: self.disable_plugin(plugin_id) ) @@ -306,8 +337,7 @@ def restart(self, config, set_active=False): try: self.plugins_manager.init(self.context, self.config) except RequiredPluginException as e: - self.show_required_plugin_dialog(e.get_plugin_id(), e.get_plugin_name(), e.get_message()) - self.required_plugin_dialog_active = True + self.show_required_plugin_dialog(e) return if set_active: diff --git a/safeeyes/ui/break_screen.py b/safeeyes/ui/break_screen.py index 7546fd83..bc826221 100644 --- a/safeeyes/ui/break_screen.py +++ b/safeeyes/ui/break_screen.py @@ -44,7 +44,7 @@ class BreakScreen: def __init__(self, context, on_skipped, on_postponed, style_sheet_path): self.context = context self.count_labels = [] - self.display = Display() + self.display = None self.enable_postpone = False self.enable_shortcut = False self.is_pretified = False @@ -56,6 +56,9 @@ def __init__(self, context, on_skipped, on_postponed, style_sheet_path): self.strict_break = False self.windows = [] + if not self.context['is_wayland']: + self.display = Display() + # Initialize the theme css_provider = Gtk.CssProvider() css_provider.load_from_path(style_sheet_path) @@ -131,7 +134,8 @@ def close(self): Hide the break screen from active window and destroy all other windows """ logging.info("Close the break screen(s)") - self.__release_keyboard() + if not self.context['is_wayland']: + self.__release_keyboard() # Destroy other windows if exists GLib.idle_add(lambda: self.__destroy_all_screens()) @@ -149,7 +153,11 @@ def __show_break_screen(self, message, image_path, widget, tray_actions): Show an empty break screen on all screens. """ # Lock the keyboard - utility.start_thread(self.__lock_keyboard) + if not self.context['is_wayland']: + utility.start_thread(self.__lock_keyboard) + else: + # TODO: Wayland keyboard locking + logging.warning("Keyboard locking not yet implemented for Wayland.") display = Gdk.Display.get_default() screen = display.get_default_screen() @@ -243,7 +251,7 @@ def __update_count_down(self, count): def __lock_keyboard(self): """ - Lock the keyboard to prevent the user from using keyboard shortcuts + Lock the keyboard to prevent the user from using keyboard shortcuts (X11 only) """ logging.info("Lock the keyboard") self.lock_keyboard = True diff --git a/safeeyes/utility.py b/safeeyes/utility.py index 80cfe403..305caa84 100644 --- a/safeeyes/utility.py +++ b/safeeyes/utility.py @@ -265,7 +265,7 @@ def desktop_environment(): env = 'unknown' if desktop_session is not None: desktop_session = desktop_session.lower() - if desktop_session in ['gnome', 'unity', 'budgie-desktop', 'cinnamon', 'mate', 'xfce4', 'lxde', 'pantheon', 'fluxbox', 'blackbox', 'openbox', 'icewm', 'jwm', 'afterstep', 'trinity', 'kde']: + if desktop_session in ['gnome', 'unity', 'budgie-desktop', 'cinnamon', 'mate', 'xfce4', 'lxde', 'pantheon', 'fluxbox', 'blackbox', 'openbox', 'icewm', 'jwm', 'afterstep', 'trinity', 'kde', 'hyprland']: env = desktop_session elif desktop_session.startswith('xubuntu') or (current_desktop is not None and 'xfce' in current_desktop): env = 'xfce' @@ -370,7 +370,7 @@ def initialize_safeeyes(): # Copy the safeeyes.json shutil.copy2(SYSTEM_CONFIG_FILE_PATH, CONFIG_FILE_PATH) - os.chmod(CONFIG_FILE_PATH, 0o777) + os.chmod(CONFIG_FILE_PATH, 0o666) create_user_stylesheet_if_missing() @@ -385,7 +385,7 @@ def create_user_stylesheet_if_missing(): # Copy the new style sheet if not os.path.isfile(STYLE_SHEET_PATH): shutil.copy2(SYSTEM_STYLE_SHEET_PATH, STYLE_SHEET_PATH) - os.chmod(STYLE_SHEET_PATH, 0o777) + os.chmod(STYLE_SHEET_PATH, 0o666) def create_startup_entry(force=False): """ @@ -493,8 +493,8 @@ def reset_config(): shutil.copy2(SYSTEM_STYLE_SHEET_PATH, STYLE_SHEET_PATH) # Add write permission (e.g. if original file was stored in /nix/store) - os.chmod(CONFIG_FILE_PATH, 0o777) - os.chmod(STYLE_SHEET_PATH, 0o777) + os.chmod(CONFIG_FILE_PATH, 0o666) + os.chmod(STYLE_SHEET_PATH, 0o666) create_startup_entry() @@ -505,7 +505,7 @@ def replace_style_sheet(): """ delete(STYLE_SHEET_PATH) shutil.copy2(SYSTEM_STYLE_SHEET_PATH, STYLE_SHEET_PATH) - os.chmod(STYLE_SHEET_PATH, 0o777) + os.chmod(STYLE_SHEET_PATH, 0o666) def initialize_logging(debug): diff --git a/setup.py b/setup.py index 480c3ab4..8e31844e 100644 --- a/setup.py +++ b/setup.py @@ -79,14 +79,14 @@ def __package_data(): setuptools.setup( name="safeeyes", - version="2.2.2", + version="2.2.3", description="Protect your eyes from eye strain using this continuous breaks reminder.", long_description=long_description, long_description_content_type="text/markdown", author="Gobinath Loganathan", author_email="slgobinath@gmail.com", url="https://github.com/slgobinath/SafeEyes", - download_url="https://github.com/slgobinath/SafeEyes/archive/v2.2.2.tar.gz", + download_url="https://github.com/slgobinath/SafeEyes/archive/v2.2.3.tar.gz", packages=setuptools.find_packages(), package_data={'safeeyes': __package_data()}, data_files=__data_files(),